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
Protocolos de rede são conjuntos de normas e regras que permitem que duas ou mais máquinas conectadas a uma rede se comuniquem entre si. Eles definem como os dados são enviados, em que formato, em que ordem e como erros são tratados.
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
O TCP (Transmission Control Protocol) é um protocolo da camada de transporte do modelo TCP/IP. Sua principal responsabilidade é 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.
TCP é um protocolo baseado em conexão que fornece um fluxo confiável de dados entre dois computadores.
Protocolo UDP
Diferente do TCP, o UDP (User Datagram Protocol) não é baseado em conexão e não garante entrega nem ordem dos dados. Ele envia pacotes independentes, chamados datagramas.
Essa abordagem faz sentido quando latência é mais importante que confiabilidade e a perda de pacotes não compromete o sistema.
Exemplos: streaming de áudio e vídeo, jogos online, DNS, comando ping.
Em alguns casos, a confiabilidade do TCP pode até prejudicar o serviço, adicionando sobrecarga desnecessária.
Portas e endereçamento
Um computador possui, em geral, uma única conexão física com a rede, mas pode executar vários programas que usam rede simultaneamente. Para isso existem as portas.
- O IP identifica a máquina
- A porta identifica a aplicação dentro da máquina
TCP e UDP usam portas para encaminhar os dados ao processo correto.
As portas variam de 0 a 65535, sendo que a porta 0 a 1023 são portas conhecidas (HTTP, HTTPS, FTP etc.) e aplicações customizadas devem usar portas acima desse intervalo.
Um endpoint é a combinação: IP + porta
Cada conexão TCP é identificada de forma única pelos dois endpoints (cliente e servidor).
O que é um socket
Um socket é uma das extremidades de um canal de comunicação bidirecional entre dois programas em execução em uma rede.
Em Java, o pacote java.net fornece as principais abstrações:
Socket → lado do cliente
ServerSocket → lado do servidor
Quando você usa Socket em Java, você já está usando TCP.
O socket não é o protocolo em si, mas a API que permite acessar o TCP.
TCP é o protocolo
Socket é a interface de programação para usá-lo
Socket vs HTTP
Ao programar diretamente com sockets, você está trabalhando em um nível mais baixo do que o HTTP.
O 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 envia a resposta 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
Muitas pessoas já usam rede em Java sem perceber. Exemplos:
- Carregar imagens via URL
- Acessar APIs HTTP
- Baixar recursos da internet
Esses são níveis mais altos de abstração, onde o Java esconde completamente sockets, TCP e detalhes de rede.
Quando precisamos de mais controle, usamos diretamente Socket e ServerSocket (TCP) OU DatagramSocket e DatagramPacket (UDP).
Comunicação cliente-servidor com sockets
Em aplicações cliente-servidor o servidor fornece um serviço e o cliente consome esse serviço.
No modelo TCP:
- O servidor cria um ServerSocket e fica escutando uma porta
- O cliente cria um Socket e se conecta ao servidor
- O servidor aceita a conexão (accept) e ambos passam a se comunicar lendo e escrevendo no socket.
A comunicação acontece por meio de objetos como InputStream, OutputStream ou abstrações como BufferedReader e PrintWriter.
Suporte a múltiplos clientes
Um servidor real precisa lidar com várias conexões simultâneas.
O padrão básico é:
while (true) {
aceitar conexão
criar uma thread para o cliente
}
Cada thread cuida de um socket específico, permitindo que múltiplos clientes sejam atendidos ao mesmo tempo.
Protocolo de aplicação
Sockets apenas transportam bytes. Para que esses bytes façam sentido, cliente e servidor precisam concordar com um protocolo.
Usar um protocolo define:
- Formato das mensagens
- Ordem das interações
- Estados possíveis
- Respostas válidas
E com isso, em sistemas reais o protocolo pode representar comandos, estados, erros, fluxos de negócio.
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 entendemos o que o HTTP resolve, porquê servidores web existem e como sistemas distribuídos realmente conversam.
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
Como foi abordado acima, no nível mais baixo que normalmente lidamos em aplicações, temos o TCP (Transmission Control Protocol) que é responsável por garantir que dados cheguem sem perdas e na ordem correta.
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.
Abaixo um exemplo de representação de um servidor e cliente usando sockets:
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();
}
}
}
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()))
) {
String message = scanner.nextLine();
out.println(message); // envia para o servidor
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
Para resolver a falta de padronização, surge o HTTP. O HTTP é um protocolo de aplicação que roda sobre o TCP e define regras claras para 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
Para padronizar aplicações web em Java, surge a Servlet API com o intuito de abstrair o HTTP em objetos Java.
Assim, o desenvolvedor passa a trabalhar com HttpServletRequest, HttpServletResponse e métodos como doGet e doPost.
Com isso, não é mais necessário abrir sockets manualmente, interpretar requisições HTTP “na unha”, 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, como Tomcat, Jetty, Undertow.
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
Enquanto a evolução do desenvolvimento Java na Web passa por Socket → Servlet → Spring, os Web Servers surgem como uma resposta a problemas de infraestrutura: escala, segurança e performance. Eles não substituem a aplicação Java nem o container de servlets, mas atuam como uma camada intermediária entre a internet e o Tomcat.
Eles ficam responsáveis principalmente por:
- 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
Porém, esses servidores não resolvem a lógica de negócio da aplicação. Eles cuidam da infraestrutura, não do domínio.
6- As primeiras abstrações Web em Java
Com o tempo, escrever HTML dentro de servlets se mostrou pouco produtivo. Surgiram então tecnologias como JSP e JSF que ajudaram a separar melhor a camada de visualização, mas também introduziram complexidade, acoplamento e dificuldade de manutenção.
Essas limitações abriram espaço para soluções mais modernas.
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, com o 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 Servlet API e Tomcat (ou outro container), 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 isso:
- Auto-configuration
- Servidor embutido
- Inicialização simples
- Menos boilerplate
Hoje, basta:
java -jar app.jar
E a aplicação está rodando e com Tomcat incluso, mesmo que o desenvolvedor nem perceba.
Conclusão
A evolução das aplicações web em Java pode ser vista como uma sequência de abstrações, cada uma resolvendo um problema específico:
- 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 baixo dessas abstrações é o que diferencia quem apenas usa frameworks de quem 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.
Top comments (0)