Por que a programação de rede em Java é um superpoder?
Imagine: você escreve código e, de repente, seu programa começa a se comunicar com outro programa do outro lado do mundo. Ele envia requisições, recebe respostas, sincroniza dados — tudo em milissegundos. Isso não é magia, é programação de rede em Java. Se você quer criar não apenas utilitários locais, mas verdadeiros sistemas distribuídos, chats, jogos online ou serviços REST — a programação de rede é essencial.
Java oferece um poderoso conjunto de ferramentas para isso: desde os clássicos Socket e ServerSocket até o de alto desempenho Java NIO (Non-blocking I/O) e os modernos WebSockets. Neste artigo, vamos abordar todas as três abordagens, escrever código funcional e entender como escolher a ferramenta certa para sua tarefa. Vamos nessa!
1. Sockets clássicos: Chat TCP "na unha"
Vamos começar pelo fundamento. Sockets em Java são o ponto de entrada no mundo TCP/IP. O servidor cria um ServerSocket, escuta uma porta e aceita conexões. O cliente cria um Socket e se conecta ao servidor. Simples como dois mais dois.
Escrevendo um servidor echo simples
O servidor recebe uma mensagem do cliente e a envia de volta (echo). O código é mínimo, mas ilustra toda a essência:
import java.io.*;import java.net.*;
public class EchoServer { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(12345)) { System.out.println("Servidor iniciado na porta 12345..."); Socket clientSocket = serverSocket.accept(); // bloqueia até conexão System.out.println("Cliente conectado: " + clientSocket.getInetAddress());
BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter( clientSocket.getOutputStream(), true);
String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("Recebido: " + inputLine); out.println("Echo: " + inputLine); if (inputLine.equalsIgnoreCase("exit")) break; } } catch (IOException e) { e.printStackTrace(); } }}E aqui está o cliente que envia mensagens:
import java.io.*;import java.net.*;
public class EchoClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 12345); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); BufferedReader stdIn = new BufferedReader( new InputStreamReader(System.in));
String userInput; System.out.println("Digite uma mensagem (exit para sair):"); while ((userInput = stdIn.readLine()) != null) { out.println(userInput); System.out.println("Resposta do servidor: " + in.readLine()); if (userInput.equalsIgnoreCase("exit")) break; } socket.close(); }}O que é importante aqui? O método accept() e readLine() bloqueiam a thread. Isso significa que enquanto um cliente se comunica, os outros esperam. A solução é o multithreading.
Servidor multithread: processando vários clientes
Para cada nova conexão, criamos uma thread separada. Usamos um pool de threads ExecutorService para não criar milhares de threads desnecessariamente:
import java.io.*;import java.net.*;import java.util.concurrent.*;
public class MultiThreadedServer { private static final int PORT = 12345; private static final ExecutorService threadPool = Executors.newFixe