Sockets
Releia aqui material sobre sockets antes de continuar.
A API usada para estabelecer a conversa via socket tem várias chamadas, que devem ser executadas na ordem certa no processo iniciando a conversa e naquele que aceita participar da mesma. Comecemos estudando o TCP.
TCP
O fluxograma da criação de um socket TCP é apresentado na seguinte figura:
Estabelecido o socket, o mesmo pode ser usado como um arquivo, isto é, lendo-se e escrevendo-se bytes. O que exatamente deve ser escrito e como o que é lido deve ser interpretado é o protocolo da camada 7, sua responsabilidade.
Considere o exemplo do uso de sockets, em Python, descrito no arquivoserver.py
.1
Ele será utilizado como base para as atividades apresentadas na sequência.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Para executá-lo, execute o seguinte comando em um terminal.
1 |
|
Em outro terminal, execute um dos dois comandos a seguir. 2
1 |
|
1 |
|
Por completude, vamos também escrever o código do cliente, agora que você já sabe que o servidor funciona. Do lado cliente, estabelece-se uma conexão apontando-se para onde está o servidor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
E para se executar o cliente, faça:
1 |
|
Observe que o socket.close()
encerra a conexão do lado de quem invoca. Na contraparte, invocações a socket.recv()
retornam com 0 bytes lidos.
Exercício: Múltiplos Pacotes
Façamos agora uma modificação no código do servidor para que envie não uma, mas três mensagens para o cliente, e que o cliente durma um pouco após receber a primeira mensagem. Isto é, modifique seu servidor assim
1 2 3 4 |
|
Agora execute novamente o cliente e veja o que acontece. Consegue explicar o fenômeno?
Modifiquemos o cliente agora, para que tenha três recv
, assim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Exercício: Ping-Pong
Modifique cliente e servidor tal que o cliente envie uma mensagem passada na linha de comando ao servidor e fique esperando uma resposta, e tal que o servidor fique esperando uma mensagem e então solicite ao operador que digite uma resposta e a envie para o cliente. O loop continua até que o usuário digite SAIR, e a conexão seja encerrada.
Terminal 1 | Terminal 2 |
---|---|
python server.py | python client.py |
Esperando conexão. | conectando-se ao servidor |
Conectado | Conectado |
Esperando mensagem | Digite mensagem: lalala |
Mensagem enviada | |
Mensagem recebida: lalala | Esperando resposta |
Digite resposta: lelele | |
Resposta enviada. | Resposta recebida: lelele |
Digite mensagem: SAIR | |
Desconectando. | |
Conexão encerrada. | |
Esperando conexão. |
Observe que para ler do teclado em Python 3 seria x = input()
.
UDP
No exemplo anterior, usamos o protocolo TCP (o padrão da API). Caso quiséssemos usar UDP, precisaríamos nos atentar a alguns detalhes.
O fluxograma da criação de um socket UDP é apresentado na seguinte figura:
A criação do socket é feita explicitando-se o uso de datagramas: s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
Um servidor UDP não executa listen
ou accept
e, em Python, simplesmente executa data, addr = sock.recvfrom(4096)
para receber o datagrama, onde data
é o conteúdo recebido e addr
o endereço de quem enviou o datagrama.
Neste caso, um mesmo socket é usado para manter comunicação com múltiplos interlocutores. Para enviar uma resposta a um interlocutor em específico, addr
é usado: sent = sock.sendto(data, addr)
, onde sent
é a quantidade de bytes enviados.
Além deste detalhe, é importante manter em mente outras características do UDP:
- falta de ordem
- falta de confiabilidade
- menos dados lidos que enviados.
- mais dados lidos que enviados (pode acontecer também no TCP)
Com tantas dificuldades para se usar o UDP, fica a questão: para que serve UDP?
Exercício: Ping-Pong UDP
Modifique o código do exercício Ping-Pong para usar UDP em vez de TCP na comunicação entre nós. Execute múltiplos clientes ao mesmo tempo. Como o seu servidor lida com isso? Modifique-o para mandar um "eco" da mensagem recebida de volta ao remetente.
Exercício: Confiabilidade UDP
Modifique o código do cliente para usar UDP em vez de TCP na comunicação entre nós. Em seguida, configure o cliente para enviar 10.000 mensagens. Configure o servidor para receber mensagens em um laço infinito, imprimindo a quantidade de mensagens recebidas. Execute múltiplos clientes ao mesmo tempo. Como o seu servidor lida com isso? Verifique se houve perda de mensagens.
IP-Multicast
Compare a figuras a seguir, representando conexões TCP para difundir a mesma informação para vários clientes.
Multicast, em oposição ao Unicast, é a capacidade de enviar mensagens para um grupo de destinatários, em vez de apenas um.
IP-Multicast é uma implementação desta ideia, usando umaa configuração específica do UDP, associada a recursos dos comutadores de rede, para otimizar o envio dos mesmos dados a múltiplos destinatários. Grupos são identificados por endereços IP especiais, conhecidos como Classe D (224.0.0.0-239.255.255.255), e propagados pela rede. A seguinte tabela descreve os usos das sub-faixas de endereços.3
Endereço | Uso |
---|---|
224.0.0.0-224.0.0.255 | Multicast local - Usado por protocolos L2, como EIGRP e OSPF |
224.0.1.0-224.0.1.255 | Multicast roteaddo - Usado por protocolos L3 |
232.0.0.0-232.255.255.255 | Source Specific Multicast - Receptores definem fontes confiáveis |
233.0.0.0-233.255.255.255 | Reservado para detentores Autonomous Systems |
239.0.0.0-239.255.255.255 | Reservado para IANA |
Resto | Uso geral |
Quando um pacote é enviado para o endereço do grupo, todos os membros do grupo recebem tal mensagem. Melhor dizendo, todos os membros podem receber a mensagem, mas como estamos falando de UDP, é possível que alguns não recebam. Além disso, não há garantia qualquer sobre a ordem de recepção das mensagens.
Exercício: IP-Multicast
Implemente e teste o seguinte receiver, colocando várias instâncias para executar em múltiplos terminais, ao mesmo tempo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Implemente e teste o seguinte sender.
1 2 3 4 5 6 7 8 |
|
-
Você pode usar outro nome, desde que não seja
socket.py
, e que adapte o comando para sua execução. ↩ -
O programa
telnet
é normalmente instalado por padrão tanto no Windows, OSX quanto no Linux. Já onetcat
normalmente precisa ser instalado por você. Em alguns sistemas, em vez denetcat
o comando é onc
. ↩