A API do soquete é o padrão de fato para as comunicações TCP / IP e UDP / IP (ou seja, o código de rede como o conhecemos). No entanto, uma de suas principais funções accept()
é um pouco mágica.
Para emprestar uma definição semi-formal:
accept () é usado no lado do servidor. Ele aceita uma tentativa de entrada recebida para criar uma nova conexão TCP do cliente remoto e cria um novo soquete associado ao par de endereços de soquete dessa conexão.
Em outras palavras, accept
retorna um novo soquete através do qual o servidor pode se comunicar com o cliente recém-conectado. O soquete antigo (no qual accept
foi chamado) permanece aberto, na mesma porta, ouvindo novas conexões.
Como accept
funciona? Como é implementado? Há muita confusão sobre esse tópico. Muitas pessoas afirmam que aceitar abre uma nova porta e você se comunica com o cliente através dela. Mas isso obviamente não é verdade, pois nenhuma porta nova é aberta. Você realmente pode se comunicar através da mesma porta com clientes diferentes, mas como? Quando vários encadeamentos chamam recv
na mesma porta, como os dados sabem para onde ir?
Eu acho que é algo semelhante ao endereço do cliente associado a um descritor de soquete, e sempre que os dados chegam, recv
eles são roteados para o soquete correto, mas não tenho certeza.
Seria ótimo obter uma explicação completa do funcionamento interno desse mecanismo.
fonte
Respostas:
Sua confusão reside em pensar que um soquete é identificado pelo IP do servidor: Porta do servidor. Na realidade, os soquetes são identificados exclusivamente por um quarteto de informações:
Client IP : Client Port
eServer IP : Server Port
Portanto, embora o IP do servidor e a porta do servidor sejam constantes em todas as conexões aceitas, as informações do lado do cliente são o que permite acompanhar onde tudo está indo.
Exemplo para esclarecer as coisas:
Digamos que temos um servidor
192.168.1.1:80
e dois clientes,10.0.0.1
e10.0.0.2
.10.0.0.1
abre uma conexão na porta local1234
e se conecta ao servidor. Agora o servidor tem um soquete identificado da seguinte maneira:Agora
10.0.0.2
abre uma conexão na porta local5678
e se conecta ao servidor. Agora o servidor tem dois soquetes identificados da seguinte maneira:fonte
Apenas para adicionar à resposta dada pelo usuário "17 de 26"
Na verdade, o soquete consiste em 5 tuplas - (ip de origem, porta de origem, ip de destino, porta de destino, protocolo). Aqui, o protocolo pode TCP ou UDP ou qualquer protocolo da camada de transporte. Este protocolo é identificado no pacote no campo 'protocol' no datagrama IP.
Portanto, é possível ter aplicativos diferentes no servidor se comunicando com o mesmo cliente exatamente nas mesmas quatro tuplas, mas diferentes no campo do protocolo. Por exemplo
Apache no lado do servidor falando (server1.com:880-client1:1234 no TCP) e World of Warcraft falando (server1.com:880-client1:1234 no UDP)
Tanto o cliente quanto o servidor tratam disso como o campo de protocolo no pacote IP nos dois casos é diferente, mesmo que todos os outros quatro campos sejam iguais.
fonte
O que me confundiu quando aprendi isso foi que os termos
socket
eport
sugerem que eles são algo físico, quando na verdade são apenas estruturas de dados que o kernel usa para abstrair os detalhes da rede.Como tal, as estruturas de dados são implementadas para poder separar conexões de diferentes clientes. Quanto à maneira como são implementadas, a resposta é a.) Não importa, o objetivo da API de sockets é precisamente que a implementação não importe ou b.) Basta dar uma olhada. Além dos livros altamente recomendados da Stevens, que fornecem uma descrição detalhada de uma implementação, consulte a fonte no Linux ou Solaris ou em um dos BSDs.
fonte
Como o outro cara disse, um soquete é identificado exclusivamente por quatro tuplas (IP do cliente, Porta do cliente, IP do servidor, Porta do servidor).
O processo do servidor em execução no IP do servidor mantém um banco de dados (o que significa que não me importo com o tipo de estrutura de tabela / lista / árvore / matriz / dados mágicos que ele usa) de soquetes ativos e escuta na porta do servidor. Quando recebe uma mensagem (através da pilha TCP / IP do servidor), verifica o IP e a porta do cliente no banco de dados. Se o IP do cliente e a porta do cliente forem encontrados em uma entrada do banco de dados, a mensagem será entregue a um manipulador existente; caso contrário, uma nova entrada de banco de dados será criada e um novo manipulador será gerado para lidar com esse soquete.
Nos primeiros dias do ARPAnet, determinados protocolos (FTP para um) escutavam uma porta especificada para solicitações de conexão e respondiam com uma porta de transferência. Comunicações adicionais para essa conexão passariam pela porta de transferência. Isso foi feito para melhorar o desempenho por pacote: os computadores eram várias ordens de magnitude mais lentas naqueles dias.
fonte