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

Published: (December 30, 2025 at 05:38 PM EST)
7 min read
Source: Dev.to

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:

  1. Comunicação baseada em conexão
  2. Entrega confiável
  3. Garantia de ordem dos dados
  4. 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:

ClasseFunção
SocketLado do cliente
ServerSocketLado do servidor
DatagramSocketLado do cliente/servidor (UDP)
DatagramPacketPacote de dados (UDP)
  • Quando você usa Socket em 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

  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 a envia pelo socket.
  7. O navegador recebe, interpreta e renderiza a página.
  8. 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: Socket e ServerSocket
  • UDP: DatagramSocket e DatagramPacket

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:

  1. Abrir a conexão
  2. Ler e escrever bytes
  3. Definir o formato das mensagens
  4. Gerenciar múltiplas conexões (threads)
  5. 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, HttpServletResponse e métodos como doGet e doPost.
  • 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:

  1. Escutar portas
  2. Gerenciar threads
  3. Implementar a Servlet API
  4. 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.

Back to Blog

Related posts

Read more »

Let's separate the separation

Introduction During the last days of 2025, our team lead took an extra day off and missed an important meeting. After a recent restructure, one colleague left...