Sockets são empregados para o envio de mensagens através de umam rede. São uma das formas mais comuns de IPC (Inter Process Communication). Nó virtual onde as entidades realizam comunicação inter-processos. As aplicações mais comuns para sockets são aplicações cliente-servidor, nas quais um servidor espera por conexões de clientes. Vamos trabalhar com sockets de internet (desenvolvido em Berkeley), os quais permitem comunicação entre hosts remotos. Um endereço de socket é uma combinação de IP com Nº de porta.
O módulo socket do Python fornece uma interface para a API de sockets BSD. Seus principais métodos e funções são:
Método | Funcionamento do método |
---|---|
socket() |
Cria o objeto socket. |
bind(endereco) |
Associa o socket servidor a um endereço. |
listen([backlog]) |
Começa a escutar pedidos de conexão. |
accept() |
Aceita uma conexão de cliente. |
connect(endereco) |
Conecta um cliente a um endereço. |
connect_ex(endereco) |
Idem anterior, retornando um indicador de erro, em vez de uma exceção, na ocorrência da chamada do connect em baixo nível. Sendo 0 a conexão deu certo, outro número indica erro. |
settimeout(tempo) |
Tempo de tentar a conexão. |
send(bytes[, flags]) |
Solicita o envio dos bytes pelo socket até que um certo conjunto de bytes seja enviado (buffer suficiente para garantir o envio). |
recv(bufsize[, flags]) |
Lê os bytes recebidos, retornando-os em uma string, até o limite de buffer definido por buffsize. |
recvfrom(bufsize[, flags]) |
Idem ao anterior, só que com UDP. |
getpeername() |
Retorna o endereço do socket remoto com o qual um socket local está associado. |
getsockname() |
Retorna o endereço do socket local. |
close()
| Fecha um socket, liberando todos os recursos alocados. |
A interface de sockets se diferencia pelos diferentes serviços que são fornecidos:
Essas são as constantes e atributos de sockets:
Criamos um objeto socket usando o método socket.socket()
, o qual recebe dois ou três parâmetros (um é opcional):
AF_INET
(endereço IPv4) e AF_INET6
(IPv6).SOCK_STREAM
(para socket TCP) e SOCK_DGRAM
(para UDP).Essa é a sequência de chamadas à API socket (interação entre um cliente e servidor):
Esse é o código do script servidor.py:
import socket
host = "localhost" # Pode ser o IP também
port = 50000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Criação do objeto, usando IPv4 e TCP.
s.bind((host, port)) # Associando o socket ao endereço localhost e sua porta
s.listen() # Escuta pedidos de conexão do cliente.
print("Aguardando conexão de um cliente...")
conn, ender = s.accept() # Aceita uma conexão de cliente.
print(f"Conectado em {ender}.")
while True:
data = conn.recv(1024) # Lê os bytes a serem recebidos e retorna uma string.
if not data:
print("Fechando a conexão!")
conn.close() # Fecha a conexão
break
conn.sendall(data) # Enviando de volta pro cliente os dados
Esse é o código do script cliente.py:
import socket
host = "localhost" # Conectando ao mesmo IP
port = 50000 # Porta de comunicação
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Criação do objeto, usando IPv4 e TCP.
s.connect((host, port)) # Conecta o cliente ao servidor
s.sendall(str.encode("Testando o envio de mensagens via socket em Python!")) # Enviando os dados pro servidor, o str.encode é para tratar acentuações.
data = s.recv(1024) # Lê os bytes recebidos pelo servidor e retorna uma string.
print(f"Mensagem ecoada: {data.decode()}") # Mensagem ecoada, com tratamento de acentuações.
Rode primeiro o servidor e depois o cliente. Ele responderá por uma porta aleatória.
Para usarmos um cliente TCP simples com um site externo, como o Google, fazemos assim:
import socket
host = "www.google.com"
port = 80
# Criando um objeto de socket com TCP:
cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Conectando o cliente:
cliente.connect((host, port))
# Enviando dados
cliente.send(str.encode("GET / HTTP / 1.1 \r \nHost: google.com \n\r\n"))
# Receber alguns dados
resposta = cliente.recv(4096)
print(resposta.decode())
No código acima, criamos um objeto socket com endereço IPv4 e cliente TCP. Conectamos nosso cliente ao servidor do Google e enviamos alguns dados, que voltarão para nós e será impresso.
Um cliente UDP não é muito diferente, fazemos apenas duas pequenas alterações para isso, como exemplificamos abaixo:
import socket
host = "127.0.0.1"
port = 9999
# Criando um objeto de socket com UDP:
cliente = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Enviamos alguns dados:
cliente.sendto(str.encode("AEIOU"), (host, port))
# Recebemos alguns dados:
endereco = cliente.recvfrom(4096)
print(endereco)
Como o UDP é um protocolo sem conexão (UDP é orientado a datagramas), usamos outros métodos, como o sendto() pra passar os dados e o recvfrom() para receber os dados. Veja o código de um servidor UDP:
import socket
host = "127.0.0.1"
port = 9999
mens = str.encode("Olá, Cliente UDP!")
serv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 e UDP
serv.bind((host, port))
print("Servidor UDP ativo...")
while True:
data = serv.recvfrom(1024)
msg = data[0].decode()
addr = data[1]
print(f"Mensagem do cliente: {msg}")
print(f"IP do cliente: {addr}")
serv.sendto(mens, addr)
Rode o servidor primeiro e depois o cliente.