socket no Python: redes TCP e UDP

Publicado em: 27/08/2026
Tempo de leitura: 7 minutos
Rustic exposed brick wall featuring aged electrical sockets and metal conduit.

O módulo socket fornece a interface de baixo nível para comunicação de rede no Python. Ele permite criar clientes e servidores TCP, trocar datagramas UDP, trabalhar com IPv4, IPv6 e sockets locais, configurar timeouts, resolver nomes e acessar opções do sistema operacional. Bibliotecas como HTTP, SMTP e bancos de dados são construídas sobre conceitos semelhantes.

Sockets transportam bytes, não mensagens Python. O programa precisa definir framing, encoding, limites, timeouts, autenticação e tratamento de desconexão. Para protocolos conhecidos, prefira uma biblioteca de alto nível; use socket quando estiver implementando ou estudando um protocolo, integrando um serviço específico ou precisando de controle detalhado.

Endereços e famílias

AF_INET representa IPv4, AF_INET6 representa IPv6 e AF_UNIX, quando disponível, representa comunicação local por pathname. O tipo mais comum para TCP é SOCK_STREAM; para UDP, SOCK_DGRAM.

import socket

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    cliente.settimeout(5)
    cliente.connect(("example.com", 80))
finally:
    cliente.close()

Use context manager para fechar o descritor automaticamente.

Conecte com create_connection

socket.create_connection() resolve o host e tenta endereços compatíveis, simplificando clientes TCP.

import socket

with socket.create_connection(("example.com", 80), timeout=5) as sock:
    sock.sendall(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
    resposta = sock.recv(4096)
    print(resposta[:100])

Para HTTP real, use uma biblioteca HTTP. O exemplo mostra apenas a camada de transporte e não implementa todos os detalhes do protocolo.

TCP é um fluxo

TCP entrega um fluxo ordenado de bytes. Uma chamada a send() no emissor não corresponde necessariamente a uma chamada a recv() no receptor. Dados podem chegar divididos ou agrupados.

O protocolo da aplicação precisa informar onde cada mensagem termina, por exemplo com tamanho prefixado, delimitador validado ou formato autodescritivo.

send e sendall

send() pode transmitir apenas parte do buffer e retorna a quantidade enviada. sendall() continua até enviar tudo ou ocorrer erro.

mensagem = b"dados importantes"
sock.sendall(mensagem)

Mesmo com sendall(), o receptor precisa montar o conteúdo completo. Um sucesso significa que os bytes foram entregues ao sistema local, não que a aplicação remota os processou.

recv e desconexão

recv(tamanho) retorna até o número solicitado. Um resultado vazio indica que o outro lado fechou a direção de envio de forma ordenada.

partes = []
while True:
    bloco = sock.recv(4096)
    if not bloco:
        break
    partes.append(bloco)
dados = b"".join(partes)

Nunca espere um recv() vazio se o protocolo mantém a conexão aberta para várias mensagens; use framing.

Framing com tamanho prefixado

Um padrão comum envia primeiro um inteiro de tamanho fixo e depois o payload.

import struct


def receber_exato(sock, quantidade):
    partes = []
    restante = quantidade
    while restante:
        bloco = sock.recv(restante)
        if not bloco:
            raise ConnectionError("conexão encerrada")
        partes.append(bloco)
        restante -= len(bloco)
    return b"".join(partes)

cabecalho = receber_exato(sock, 4)
tamanho = struct.unpack("!I", cabecalho)[0]
if tamanho > 1_000_000:
    raise ValueError("mensagem grande demais")
payload = receber_exato(sock, tamanho)

Valide o tamanho antes de alocar memória para evitar exaustão.

Servidor TCP básico

Um servidor cria o socket, associa um endereço, escuta e aceita conexões.

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as servidor:
    servidor.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    servidor.bind(("127.0.0.1", 9000))
    servidor.listen()
    conexao, endereco = servidor.accept()
    with conexao:
        conexao.sendall(b"ola\n")

Associar a 127.0.0.1 limita acesso à máquina local. Usar endereço vazio ou todas as interfaces expõe o serviço à rede e exige autenticação, firewall e hardening.

listen e backlog

listen() coloca o socket em modo passivo. O backlog controla uma fila de conexões pendentes, mas o comportamento exato depende do sistema.

Um backlog grande não resolve um servidor lento. Aceite conexões rapidamente, limite clientes e aplique timeouts.

accept cria outro socket

accept() devolve um novo socket conectado e o endereço remoto. O socket de escuta continua disponível para novos clientes.

Feche ambos de forma independente. Um vazamento de conexões aceitas esgota descritores.

Concorrência no servidor

Um servidor simples trata um cliente por vez. Para vários clientes, use threads, processos, selectors ou asyncio. A escolha depende de quantidade de conexões, workload e complexidade.

O artigo de select no Python mostra multiplexação de descritores. Não crie uma thread ilimitada por conexão sem controles.

Timeouts

settimeout(segundos) limita operações bloqueantes.

sock.settimeout(10)
try:
    dados = sock.recv(4096)
except socket.timeout:
    registrar_aviso("cliente inativo")

Defina timeouts para conexão, leitura e escrita de acordo com o protocolo. Uma conexão sem deadline pode prender workers indefinidamente.

Modo não bloqueante

setblocking(False) faz operações retornarem imediatamente e gerarem BlockingIOError quando ainda não podem avançar.

Não implemente busy loop. Use selectors, select ou um event loop para aguardar readiness.

UDP

UDP envia datagramas independentes sem conexão confiável, ordenação ou retransmissão automática.

import socket

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
    sock.settimeout(2)
    sock.sendto(b"consulta", ("127.0.0.1", 9999))
    dados, origem = sock.recvfrom(2048)
    print(origem, dados)

Datagramas podem ser perdidos, duplicados, reordenados ou truncados se o buffer for pequeno. O protocolo da aplicação decide retries e idempotência.

Tamanho de UDP

Embora o protocolo permita datagramas grandes, redes reais têm limites de MTU e fragmentação. Mensagens pequenas são mais robustas. Para payloads extensos ou confiabilidade, use TCP ou um protocolo apropriado.

Resolução de nomes

getaddrinfo() resolve nomes para endereços e retorna alternativas de família e tipo.

for resultado in socket.getaddrinfo("example.com", 443, type=socket.SOCK_STREAM):
    familia, tipo, protocolo, canonico, endereco = resultado
    print(familia, endereco)

DNS pode ser lento, falhar ou retornar vários endereços. Não fixe a primeira resposta para sempre sem política de cache.

IPv4 e IPv6

Use getaddrinfo() e tente os endereços retornados em vez de assumir IPv4. IPv6 usa tuplas de endereço diferentes e pode exigir configuração específica de dual stack.

Teste em ambientes IPv4-only, IPv6-only e dual stack.

Portas e ordem de bytes

Portas variam de 0 a 65535. Portas baixas podem exigir privilégios. Funções como htons(), htonl(), ntohs() e ntohl() convertem ordem de bytes para campos binários, embora struct com prefixo ! seja comum em protocolos.

SO_REUSEADDR

SO_REUSEADDR pode facilitar reinício de servidores após conexões em estados de encerramento. A semântica varia por sistema e não deve ser interpretada como autorização para vários servidores concorrentes na mesma porta.

Configure opções antes de bind().

Keepalive

SO_KEEPALIVE habilita probes do sistema para detectar conexões quebradas, mas intervalos padrão podem ser longos e opções específicas variam.

Keepalive não substitui heartbeat e deadline no protocolo da aplicação.

shutdown

shutdown(socket.SHUT_WR) informa que o programa não enviará mais dados, mantendo a possibilidade de receber uma resposta. close() libera o descritor local.

Use half-close somente quando o protocolo o compreender. Um peer pode tratar como encerramento total.

TLS

Um socket TCP comum não oferece confidencialidade, autenticação ou integridade contra intermediários. Para protocolos seguros, envolva a conexão com ssl.SSLContext configurado corretamente ou use uma biblioteca de alto nível.

Não crie criptografia própria e não desative verificação de certificado para “resolver” erros.

Encoding

A rede transporta bytes. Defina explicitamente o encoding para texto.

mensagem = "olá".encode("utf-8")
sock.sendall(mensagem)
texto = dados.decode("utf-8", errors="strict")

Delimitadores devem ser definidos em bytes e o protocolo precisa tratar caracteres inválidos.

Segurança de entrada

Limite tamanho, profundidade, quantidade de campos e tempo de processamento. Não passe dados de rede diretamente a eval(), shell, SQL ou deserializadores inseguros.

Autentique clientes quando necessário e aplique autorização por operação.

Slow clients

Um cliente pode enviar poucos bytes lentamente e ocupar um worker. Use deadlines, tamanho mínimo por progresso, limites de conexão e multiplexação.

Rate limiting e backpressure devem proteger memória e serviços downstream.

Erros transitórios

Conexões podem falhar por DNS, timeout, reset, rota, recusa e indisponibilidade temporária. Refaça apenas operações idempotentes e use atraso exponencial com limite.

Não repita indefinidamente nem transforme falha de autenticação em retry.

Endereços locais Unix

Quando AF_UNIX estiver disponível, processos da mesma máquina podem comunicar-se por pathname com menos exposição à rede.

Gerencie permissões do arquivo do socket, remova paths órfãos e limite acesso ao diretório.

Testes

Teste pacotes divididos, vários frames juntos, EOF, timeout, reset, endereço inválido, IPv6, DNS com várias respostas, cliente lento, payload máximo, conexão simultânea, shutdown e indisponibilidade de rede.

Use sockets locais e portas efêmeras em testes. Não dependa de serviços públicos.

Observabilidade

Registre endereço, duração, bytes, estado do protocolo e erro sem armazenar segredos ou payloads sensíveis. Métricas de conexões ativas, timeouts, resets e filas ajudam a detectar saturação.

Erros comuns

Os erros mais frequentes são presumir que recv() retorna uma mensagem completa, ignorar retorno de send(), não usar timeout, expor o servidor em todas as interfaces, confiar em UDP, bloquear uma thread por cliente sem limite, usar DNS como identidade e transportar dados sensíveis sem TLS.

Conclusão

socket oferece controle direto sobre a rede, mas exige um protocolo explícito. Defina framing, limites, timeouts, segurança, lifecycle e estratégia de concorrência antes de colocar o serviço em produção.

Consulte a documentação oficial de socket e select no Python para multiplexar várias conexões.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    multiprocessing no Python: vários núcleos

    Aprenda multiprocessing no Python com processos, pools, filas, pipes, memória compartilhada, cancelamento, segurança e shutdown correto.

    Ler mais

    Tempo de leitura: 7 minutos
    26/08/2026
    Monochrome image showcasing concentric circles in a tunnel-like structure creating a sense of depth.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    concurrent.futures: threads e processos em paralelo

    Aprenda concurrent.futures no Python com threads, processos, Future, timeouts, cancelamento, backpressure e prevenção de deadlocks.

    Ler mais

    Tempo de leitura: 7 minutos
    26/08/2026
    Striking image of a red-bellied python showcasing its vibrant scales in dramatic lighting.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    winsound no Python: sons no Windows

    Aprenda winsound no Python para tocar WAV, sons do sistema, beeps, loops e notificações assíncronas com segurança no Windows.

    Ler mais

    Tempo de leitura: 7 minutos
    26/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    winreg no Python: Registro do Windows

    Aprenda winreg no Python para ler e gravar o Registro do Windows, controlar permissões, tipos, WOW64, exclusões e segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    26/08/2026
    Macro shot capturing detailed patterns of a python in its natural surroundings.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    posix no Python: chamadas Unix diretas

    Entenda posix no Python, chamadas Unix, descritores, permissões, processos, segurança e quando usar os em vez do módulo direto.

    Ler mais

    Tempo de leitura: 7 minutos
    26/08/2026
    A male software engineer working on code in a modern office setting.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    curses no Python: interfaces no terminal

    Aprenda curses no Python para criar interfaces de terminal com janelas, cores, teclado, resize, Unicode e cleanup seguro.

    Ler mais

    Tempo de leitura: 7 minutos
    26/08/2026