DEV Community

Jeronima Floriano
Jeronima Floriano

Posted on

Do Socket ao Spring Boot: entendendo a comunicação via rede em Java

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:

  1. O navegador cria um socket TCP
  2. Conecta-se ao servidor em uma porta específica (ex: 80 ou 443)
  3. Envia uma requisição HTTP pelo socket
  4. O servidor recebe bytes brutos
  5. O servidor interpreta o protocolo HTTP
  6. O servidor gera uma resposta HTTP e envia a resposta pelo socket
  7. 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();
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
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);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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)