Do Socket ao Spring Boot: entendendo a comunicação via rede em Java
Source: Dev.to
Comunicação entre Sistemas Distribuídos
Quando falamos em comunicação entre sistemas, especialmente no contexto de aplicações distribuídas, estamos lidando com um conjunto de conceitos que muitas vezes ficam escondidos por frameworks e abstrações de alto nível. Entender esses fundamentos ajuda a compreender melhor como APIs, servidores web e integrações realmente funcionam “por baixo dos panos”.
Protocolos de Rede
Na prática, quando um sistema conversa com outro, não existe “mágica”: existe uma pilha de protocolos, cada um resolvendo um problema específico.
O papel do TCP/IP
- Camada de transporte do modelo TCP/IP.
- Responsável por garantir que os dados enviados de um ponto cheguem corretamente ao outro.
O TCP oferece:
- Comunicação baseada em conexão
- Entrega confiável
- Garantia de ordem dos dados
- Retransmissão automática em caso de falhas
Por isso, ele é amplamente utilizado em cenários onde integridade e consistência são essenciais, como na comunicação HTTP.
Resumo: TCP é um protocolo baseado em conexão que fornece um fluxo confiável de dados entre dois computadores.
Protocolo UDP
- Não estabelece conexão, o que reduz a latência.
- Adequado quando a perda de pacotes não compromete o sistema (ex.: streaming de áudio/vídeo, jogos online).
- Em alguns casos, a confiabilidade do TCP pode até prejudicar o serviço, adicionando sobrecarga desnecessária.
Portas e Endereçamento
- IP identifica a máquina.
- Porta identifica a aplicação dentro da máquina.
- TCP e UDP usam portas para encaminhar os dados ao processo correto.
Endpoint = combinação
IP + porta.
Cada conexão TCP é identificada de forma única pelos dois endpoints (cliente e servidor).
O que é um Socket?
Em Java, o pacote java.net fornece as principais abstrações:
| Classe | Função |
|---|---|
Socket | Lado do cliente |
ServerSocket | Lado do servidor |
DatagramSocket | Lado do cliente/servidor (UDP) |
DatagramPacket | Pacote de dados (UDP) |
- Quando você usa
Socketem Java, já está usando TCP (o protocolo). - HTTP é um protocolo de aplicação que roda em cima do TCP e usa sockets internamente. Ou seja, HTTP nada mais é do que uma convenção de mensagens (requisição e resposta) que trafegam por um socket TCP.
Como o HTTP funciona “por baixo” quando um navegador acessa uma página web
- O navegador cria um socket TCP.
- Conecta‑se ao servidor em uma porta específica (ex.: 80 ou 443).
- Envia uma requisição HTTP pelo socket.
- O servidor recebe bytes brutos.
- O servidor interpreta o protocolo HTTP.
- O servidor gera uma resposta HTTP e a envia pelo socket.
- O navegador recebe, interpreta e renderiza a página.
- A conexão pode ser encerrada ou mantida aberta (keep‑alive), dependendo da versão do HTTP e dos headers.
Programação em Rede em Java
Níveis de abstração mais altos
- Carregar imagens via URL
- Acessar APIs HTTP
- Baixar recursos da internet
Nesses casos, o Java esconde completamente sockets, TCP e detalhes de rede.
Quando precisamos de mais controle
- TCP:
SocketeServerSocket - UDP:
DatagramSocketeDatagramPacket
Comunicação cliente‑servidor com sockets (modelo TCP)
// Servidor
ServerSocket serverSocket = new ServerSocket(4001);
Socket clientSocket = serverSocket.accept();
PrintStream out = new PrintStream(clientSocket.getOutputStream());
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = reader.readLine()) != null) {
out.println("Server received: " + inputLine);
}
// Cliente
Socket socket = new Socket("localhost", 4001);
Scanner scanner = new Scanner(System.in);
PrintStream out = new PrintStream(socket.getOutputStream());
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String message = scanner.nextLine();
out.println(message); // envia para o servidor
String response = reader.readLine(); // lê a resposta
System.out.println("Response: " + response);
Suporte a múltiplos clientes
while (true) {
Socket client = serverSocket.accept(); // aceita nova conexão
new Thread(() -> handleClient(client)).start(); // cada thread cuida de um socket
}
Protocolo de Aplicação
Usar um protocolo define:
- Formato das mensagens
- Ordem das interações
- Estados possíveis
- Respostas válidas
Em sistemas reais, o protocolo pode representar comandos, estados, erros e fluxos de negócio.
Da Comunicação via Socket ao Spring Boot
Quando começamos a trabalhar com frameworks como Spring Boot, é comum esquecer que, por baixo de tantas abstrações, tudo ainda se resume à troca de bytes pela rede. Entender essa evolução ajuda não só a escrever código melhor, mas também a tomar decisões arquiteturais mais conscientes.
1️⃣ O ponto de partida: TCP e Sockets
Em Java, a forma mais direta de usar TCP é através de sockets. Ao trabalhar diretamente com sockets, o desenvolvedor precisa cuidar de tudo:
- Abrir a conexão
- Ler e escrever bytes
- Definir o formato das mensagens
- Gerenciar múltiplas conexões (threads)
- Tratar falhas e encerramento de conexões
Apesar de poderoso, esse modelo rapidamente se torna difícil de manter. Cada aplicação acaba criando seu próprio “protocolo” e o código fica altamente acoplado à infraestrutura de rede.
Exemplo completo de servidor e cliente usando sockets
// Server.java
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(4001);
Socket clientSocket = serverSocket.accept();
PrintStream out = new PrintStream(clientSocket.getOutputStream());
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()))) {
String inputLine;
while ((inputLine = reader.readLine()) != null) {
out.println("Server received: " + inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Client.java
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 4001);
Scanner scanner = new Scanner(System.in);
PrintStream out = new PrintStream(socket.getOutputStream());
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
System.out.print("Enter message: ");
String message = scanner.nextLine();
out.println(message); // envia para o servidor
String response = reader.readLine(); // lê a resposta
System.out.println("Response: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Por que migrar para frameworks como Spring Boot?
- Abstração de baixo nível: Spring cuida de conexões, thread‑pools, timeouts, etc.
- Padronização: Uso de REST, WebFlux, Spring MVC, que já implementam protocolos de aplicação consolidados.
- Facilidade de teste: Mocks e testes de integração são mais simples.
- Escalabilidade: Integração com servidores de aplicação (Tomcat, Jetty, Undertow) e com containers Docker/Kubernetes.
Entender TCP, UDP e sockets é entender a base da comunicação entre sistemas. Frameworks como Spring, servidores como Tomcat e protocolos como HTTP existem para facilitar a vida, mas todos eles dependem desses conceitos fundamentais. Quando estudamos sockets, compreendemos o que o HTTP resolve, por que servidores web existem e como sistemas distribuídos realmente conversam.
String response = reader.readLine(); // lê resposta do servidor
System.out.println("Resposta do servidor: " + response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
2 – HTTP: padronizando a comunicação
- Métodos: GET, POST, PUT, PATCH, DELETE
- Cabeçalhos
- Códigos de status
- Formato de requisição e resposta
Com isso, clientes e servidores passam a “falar a mesma língua”, navegadores se tornam possíveis e APIs começam a surgir de forma consistente.
Importante: HTTP não substitui o socket; ele apenas organiza o que é transmitido por ele.
3 – Servlet API: a entrada do Java no mundo Web
- O desenvolvedor passa a trabalhar com
HttpServletRequest,HttpServletResponsee métodos comodoGetedoPost. - Não é mais necessário abrir sockets manualmente, interpretar requisições HTTP “na unha” ou lidar diretamente com concorrência de conexões.
- O foco passa a ser a requisição HTTP, não a rede.
4 – Servlet Containers: onde o Tomcat entra
Alguém ainda precisa:
- Escutar portas
- Gerenciar threads
- Implementar a Servlet API
- Controlar o ciclo de vida da aplicação
Esse é o papel dos Servlet Containers (Tomcat, Jetty, Undertow, etc.).
O Tomcat, por exemplo
- Abre sockets TCP
- Processa HTTP
- Instancia servlets
- Delega a execução para o código da aplicação
5 – Web Servers: lidando com conexões em escala
Responsabilidades principais:
- Encerrar conexões TCP e TLS
- Atuar como reverse proxy
- Servir conteúdo estático com alta performance
- Proteger e aliviar carga do container de aplicação
Esses servidores não resolvem a lógica de negócio da aplicação; cuidam da infraestrutura, não do domínio.
6 – As primeiras abstrações Web em Java
Com o tempo, escrever HTML dentro de servlets mostrou-se pouco produtivo. Surgiram tecnologias como JSP e JSF, que ajudaram a separar melhor a camada de visualização, mas também introduziram:
- Complexidade
- Acoplamento
- Dificuldade de manutenção
7 – Spring Framework: desacoplamento e organização
O Spring nasce para resolver problemas estruturais do desenvolvimento Java:
- Alto acoplamento
- Dificuldade de testes
- Dependências rígidas
No contexto web (Spring MVC), o desenvolvedor
- Não precisa estender
HttpServlet - Trabalha com controllers
- Define rotas por anotações
- Separa claramente responsabilidades
O Spring continua rodando sobre a Servlet API e um container (Tomcat ou outro), mas abstrai quase completamente esses detalhes.
8 – Spring Boot: produtividade máxima
Mesmo com Spring, a configuração ainda era extensa. O Spring Boot surge para simplificar tudo:
- Auto‑configuration
- Servidor embutido
- Inicialização simples
- Menos boilerplate
Hoje, basta
java -jar app.jar
E a aplicação está rodando com Tomcat incluso, mesmo que o desenvolvedor nem perceba.
Conclusão
Evolução da comunicação e programação
TCP → Socket → HTTP → Servlet API → Spring → Spring Boot
Evolução da infraestrutura
Web Servers (Apache/Nginx) → Servlet Containers (Tomcat/Jetty)
Cada camada reduz complexidade, aumenta produtividade e afasta o desenvolvedor dos detalhes de baixo nível, mas entender o que existe por trás dessas abstrações diferencia quem apenas usa frameworks de quem realmente arquitetura sistemas.
No fim das contas, toda requisição HTTP ainda começa e termina em um socket TCP, mesmo quando estamos usando Spring Boot.