Por que Go é a linguagem ideal para programação de rede?
\n\nSe você já escreveu um servidor de rede em Python (especialmente usando socket ou asyncio), sabe como o código pode rapidamente se transformar em um labirinto de callbacks e loops de eventos. Go (Golang) resolve esse problema no nível arquitetural: goroutines e canais tornam o trabalho assíncrono com rede tão simples quanto escrever código sequencial.
Neste artigo, vamos explorar a programação de rede em Go na prática. Você aprenderá como montar um chat TCP completo, enviar um pacote UDP e iniciar um servidor HTTP com roteamento em apenas 15 minutos. Todos os exemplos são funcionais — você pode copiá-los e executá-los.
\n\nFundamentos: o pacote net e seu superpoder
\n\nEm Go, toda a mágica de rede está no pacote padrão net. Ele fornece uma interface unificada para trabalhar com TCP, UDP, sockets Unix e até SSL/TLS. O grande diferencial é que as funções Listen, Dial e Accept funcionam de forma síncrona, mas não bloqueiam todo o programa, porque cada goroutine é leve.
Vamos direto ao ponto.
\n\nServidor TCP: um chat em 10 linhas
\n\nVamos criar um simples servidor echo, que aceita conexões e envia de volta o que recebeu. Isso é um clássico da programação de rede em Go.
\n\npackage main\n\nimport (\n "bufio"\n "fmt"\n "net"\n)\n\nfunc handleConnection(conn net.Conn) {\n defer conn.Close()\n scanner := bufio.NewScanner(conn)\n for scanner.Scan() {\n message := scanner.Text()\n fmt.Printf("Recebido: %s\\n", message)\n conn.Write([]byte("Echo: " + message + "\\n"))\n }\n}\n\nfunc main() {\n listener, _ := net.Listen("tcp", ":8080")\n fmt.Println("Servidor TCP rodando na porta :8080")\n for {\n conn, _ := listener.Accept()\n go handleConnection(conn) // cada goroutine é um cliente separado\n }\n}\n\nO que está acontecendo aqui?
\n- \n
net.Listen("tcp", ":8080")— cria um listener TCP na porta 8080. \n - O loop infinito
foraceita novas conexões viaAccept(). \n - Cada conexão é tratada em uma goroutine separada
go handleConnection(). \n - Dentro da função, lemos linhas com
bufio.Scannere enviamos a resposta. \n
Execute este código, abra um terminal e conecte-se via nc localhost 8080 (ou Putty). Qualquer mensagem enviada retornará com o prefixo "Echo:". Incrivelmente, este já é um servidor de rede completo, capaz de atender milhares de clientes sem um único callback.
UDP: entrega rápida sem garantias
\n\nSe TCP é como uma chamada telefônica (conexão estabelecida — conversamos), UDP é como enviar cartões postais: você manda e esquece. Go torna o trabalho com UDP igualmente simples.
\n\nCliente e servidor UDP
\n\n// Servidor\npackage main\n\nimport (\n "fmt"\n "net"\n)\n\nfunc main() {\n addr, _ := net.ResolveUDPAddr("udp", ":8081")\n conn, _ := net.ListenUDP("udp", addr)\n defer conn.Close()\n\n buffer := make([]byte, 1024)\n for {\n n, clientAddr, _ := conn.ReadFromUDP(buffer)\n message := string(buffer[:n])\n fmt.Printf("Recebido de %s: %s\\n", clientAddr, message)\n conn.WriteToUDP([]byte("Recebido: "+message+"\\n"), clientAddr)\n }\n}\n\n// Cliente\n// Em um arquivo separado ou goroutine:\nconn, _ := net.Dial("udp", "localhost:8081")\ndefer conn.Close()\nconn.Write([]byte("Olá, UDP!"))\nbuffer := make([]byte, 1024)\nn, _ := conn.Read(buffer)\nfmt.Println(string(buffer[:n]))\n\nDiferença chave do TCP:
\n- \n
- Não há
Accept()— apenas escutamos a porta e lemos datagramas. \n - Cada pacote chega com o endereço do remetente. \n
- O Go gerencia o buffer automaticamente:
ReadFromUDPretorna o endereço de quem enviou. \n