Programação em Rede com C++: de Sockets a Async
\n\nVocê já se perguntou como funcionam chats, jogos online ou servidores web? Por trás de cada um deles, está a comunicação em rede. E se você quer criar aplicações de rede rápidas, confiáveis e de baixo nível, a programação em rede com C++ é o caminho certo. Neste artigo, não vamos apenas falar de teoria: vamos escrever código de verdade, desde um simples chat TCP até um servidor assíncrono usando Boost.Asio. Prepare suas IDEs — vai ser divertido!
\n\nPor que C++ para Redes? Três Motivos
\nMuitos escolhem Python ou Java para tarefas de rede, mas o C++ oferece três vantagens cruciais:
\n- \n
- Velocidade: Overhead mínimo, acesso direto a chamadas de sistema (syscalls). \n
- Controle: Você gerencia memória, buffers e timings manualmente. \n
- Ecossistema:
Boost.Asio,libcurl,Poco— bibliotecas poderosas para qualquer desafio. \n
Mas com grandes poderes vêm grandes responsabilidades: um único erro no gerenciamento de sockets pode derrubar seu servidor. Vamos entender como evitar isso.
\n\nFundamentos: Sockets e o Modelo OSI
\nAntes de escrever código, vamos lembrar o que é um socket. É uma abstração que permite a um aplicativo enviar e receber dados pela rede. Em C++, trabalhamos com sys/socket.h (Linux) ou winsock2.h (Windows).
TCP vs UDP: Quando Usar Cada Um?
\n- \n
- TCP (SOCK_STREAM): Garante entrega e ordem dos pacotes. Ideal para chats, HTTP, bancos de dados. \n
- UDP (SOCK_DGRAM): Mais rápido, mas sem garantias. Usado em streaming, DNS, jogos online (onde perder um pacote é melhor que ter latência). \n
Criando um Servidor e Cliente TCP em C++ (Sockets Puros)
\nVamos construir um servidor echo simples. Ele recebe uma mensagem e a envia de volta. Este é o clássico "Hello, World" da programação em rede com C++.
\n\nLado do Servidor (echo_server.cpp)
\n#include <iostream>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <unistd.h>\n#include <cstring>\n\nint main() {\n int server_fd, client_fd;\n struct sockaddr_in address;\n int opt = 1;\n int addrlen = sizeof(address);\n char buffer[1024] = {0};\n\n // 1. Criando o socket\n if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n perror("socket failed");\n exit(EXIT_FAILURE);\n }\n\n // 2. Vinculando à porta (com opção reuse port)\n if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {\n perror("setsockopt");\n exit(EXIT_FAILURE);\n }\n address.sin_family = AF_INET;\n address.sin_addr.s_addr = INADDR_ANY;\n address.sin_port = htons(8080);\n\n if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {\n perror("bind failed");\n exit(EXIT_FAILURE);\n }\n\n // 3. Ouvindo conexões de entrada\n if (listen(server_fd, 3) < 0) {\n perror("listen");\n exit(EXIT_FAILURE);\n }\n\n std::cout << "Servidor rodando na porta 8080. Aguardando conexões..." << std::endl;\n\n // 4. Aceitando um cliente\n if ((client_fd = accept(server_fd, (struct sockaddr *)&address,\n (socklen_t*)&addrlen)) < 0) {\n perror("accept");\n exit(EXIT_FAILURE);\n }\n\n // 5. Lendo e enviando de volta (echo)\n int valread = read(client_fd, buffer, 1024);\n std::cout << "Recebido: " << buffer << std::endl;\n send(client_fd, buffer, strlen(buffer), 0);\n std::cout << "Resposta echo enviada" << std::endl;\n\n close(client_fd);\n close(server_fd);\n return 0;\n}\n\nLado do Cliente (echo_client.cpp)
\n#include <