Skip to main content

Módulo socket



socket


O módulo socket é a base da programação de rede em Python. Ele permite que programas enviem e recebam dados entre máquinas diferentes, ou mesmo dentro da mesma máquina, usando protocolos de rede como TCP e UDP.


O conceito de socket é uma abstração que representa um ponto final de comunicação, como um conector digital entre dois programas. No contexto de rede, um socket envolve uma combinação de endereço IP, número de porta e protocolo de transporte. Em Python, o módulo socket fornece a interface para criar, configurar, enviar e receber dados através desses conectores.


Para iniciar, a primeira coisa que se faz é criar um objeto de socket com socket.socket(), especificando o tipo de conexão desejada. Por exemplo, socket.AF_INET indica que se usará IPv4, e socket.SOCK_STREAM representa o uso do protocolo TCP, que é orientado a conexão. A partir daí, é possível configurar o socket como servidor ou cliente.


Um servidor deve primeiro fazer o bind() de seu socket a um endereço IP e porta, depois usar o listen() para aceitar conexões e finalmente chamar accept(), que bloqueia a execução até que um cliente tente se conectar.


Esse accept() devolve dois valores, o novo socket de conexão e o endereço do cliente. O novo socket é usado para enviar e receber dados com aquele cliente em particular, enquanto o socket original continua ouvindo novas conexões.


O cliente, por sua vez, apenas precisa criar o socket e usar o método connect() para se ligar ao endereço do servidor. Uma vez que a conexão esteja estabelecida, ambos os lados podem usar os métodos send() e recv() para troca de dados.


Além do protocolo TCP, o módulo também permite trabalhar com UDP através do uso de socket.SOCK_DGRAM. Nesse caso, não há conexão persistente: o sendto() envia uma mensagem diretamente a um endereço, e o recvfrom() lê dados informando de onde vieram. É ideal para comunicação leve e rápida, onde não se exige confiabilidade total.


Outros métodos relevantes incluem settimeout() para definir um tempo máximo de espera em operações de rede, close() para encerrar um socket e liberar os recursos associados, getsockname() para descobrir a porta que foi realmente atribuída em um bind com porta zero, entre outros. Em sistemas modernos, também é possível usar IPv6 com AF_INET6 ou trabalhar com sockets de domínio Unix com AF_UNIX.


Um aspecto importante é o fato de que a comunicação com sockets pode ser bloqueante, ou seja, o programa pode parar a execução enquanto espera dados. Por isso, é comum configurar sockets com tempo limite ou usar abordagens com select ou asyncio para permitir múltiplas conexões simultâneas sem travar o programa.


Toda a base da comunicação entre processos distribuídos, servidores HTTP, clientes SMTP e sistemas de chat, por exemplo, pode ser implementada diretamente com socket. Embora bibliotecas mais sofisticadas como requests, asyncio ou websockets escondam esse nível de detalhe, elas por trás usam a mesma base fornecida por esse módulo. O uso do socket oferece o controle total sobre cada parte da conexão e do protocolo, sendo indispensável para entender como funciona a comunicação entre máquinas, desde o envio de bytes até a espera por resposta. Isso torna o módulo essencial não só para redes, mas também para entender a forma como a internet funciona no nível mais básico.



Família e Protocolos


Os tipos AF_... e SOCK_... no módulo socket do Python indicam, respectivamente, a família de endereços e o tipo de protocolo que será usado pelo socket. Os identificadores que começam com AF_ determinam o formato do endereço que o socket vai aceitar. O mais comum é o AF_INET, que representa endereços IPv4 e é usado junto com uma porta, por exemplo: ("127.0.0.1", 8000).


Existe também o AF_INET6, que permite criar sockets para trabalhar com endereços IPv6, como ("::1", 8000, 0, 0). Outro valor possível é AF_UNIX, que representa sockets de domínio Unix, onde o endereço é um caminho de arquivo do sistema local, como "/tmp/socket", sendo usado apenas para comunicação entre processos na mesma máquina, disponível apenas em sistemas Unix.


Já os valores SOCK_ definem o tipo de comunicação. O SOCK_STREAM representa uma conexão com fluxo contínuo de dados e é usado com o protocolo TCP, sendo o mais comum para conexões confiáveis e persistentes.


O SOCK_DGRAM representa uma comunicação por datagramas, ou seja, pacotes isolados sem conexão fixa, e é usado com o protocolo UDP. Outro valor possível é o SOCK_RAW, que permite enviar e receber pacotes com cabeçalhos personalizados, usado em casos de comunicação de baixo nível, como construção de pacotes ICMP para ferramentas como ping, exigindo permissões especiais do sistema operacional.


Também há SOCK_SEQPACKET, menos comum, que funciona como SOCK_STREAM mas mantém os limites das mensagens, usado em algumas aplicações mais específicas, geralmente com AF_UNIX.



Criptografia


Por padrão, a comunicação feita com o módulo socket não é criptografada. Quando você cria um socket com socket.socket(AF_INET, SOCK_STREAM) ou SOCK_DGRAM, está usando diretamente o protocolo TCP ou UDP, que por padrão transmite os dados em texto puro.


Isso significa que qualquer dado enviado por esse socket pode ser interceptado e lido por terceiros que estejam entre o cliente e o servidor, como roteadores ou sniffers em redes locais.


Se for necessário criptografar a comunicação, é preciso envolver o socket em uma camada de segurança, como TLS. Isso pode ser feito com o módulo ssl da biblioteca padrão do Python, que permite encapsular um socket TCP para que a troca de dados seja criptografada. O ssl.wrap_socket() ou a função moderna ssl.create_default_context().wrap_socket() transformam um socket comum em um socket seguro, compatível com HTTPS, SMTPS, IMAPS e outros protocolos que usam TLS.