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á onetcatnormalmente precisa ser instalado por você. Em alguns sistemas, em vez denetcato comando é onc. ↩