Como o servidor descobre para qual porta do cliente enviar?

26

Pelo que entendi, é isso que acontece quando um cliente faz uma solicitação de conexão:

  1. O servidor será vinculado a um número de porta específico. O número da porta está sempre vinculado a um processo de atendimento. Como apenas o servidor está escutando as conexões de entrada, não precisamos vincular no lado do cliente
  2. O servidor continuará ouvindo esse número da porta.
  3. O cliente enviará uma connect()solicitação.
  4. O servidor aceitará a solicitação usando accept(). Assim que o servidor aceita a solicitação do cliente, o kernel aloca um número de porta aleatório para o servidor por mais tempo send()e receive(), como o mesmo número de porta no servidor não pode ser usado para enviar e ouvir, e a porta anterior ainda está ouvindo novas conexões

Dado tudo isso, como o servidor descobre em qual porta o cliente está recebendo? Sei que o cliente enviará segmentos TCP com uma porta de origem e uma porta de destino; portanto, o servidor usará a porta de origem desse segmento como porta de destino, mas que função o servidor chama para descobrir sobre essa porta? É isso accept()?

Subi Suresh
fonte

Respostas:

33

Faz parte do cabeçalho TCP (ou UDP, etc.), no pacote. Portanto, o servidor descobre porque o cliente diz. É semelhante a como ele descobre o endereço IP do cliente (que faz parte do cabeçalho IP).

Por exemplo, todo pacote TCP inclui um cabeçalho IP (com IP de origem, IP de destino e protocolo [TCP], pelo menos). Depois, há um cabeçalho TCP (com porta de origem e destino, além de mais).

Quando o kernel recebe um pacote SYN (o início de uma conexão TCP) com um IP remoto de 10.11.12.13 (no cabeçalho IP) e uma porta remota de 12345 (no cabeçalho TCP), ele conhece o IP e a porta remotos . Ele envia de volta um SYN | ACK. Se receber um ACK de volta, a listenchamada retornará um novo soquete, configurado para essa conexão.

Um soquete TCP é identificado exclusivamente pelos quatro valores (IP remoto, IP local, porta remota, porta local). Você pode ter várias conexões / soquetes, desde que pelo menos um deles seja diferente.

Normalmente, a porta local e o IP local serão os mesmos para todas as conexões com um processo do servidor (por exemplo, todas as conexões com o sshd estarão em local-ip: 22). Se uma máquina remota fizer várias conexões, cada uma usará uma porta remota diferente. Portanto, tudo, menos a porta remota, será a mesma, mas tudo bem - apenas um dos quatro deve ser diferente.

Você pode usar, por exemplo, wirehsark para ver o pacote, e ele rotulará todos os dados para você. Aqui está a porta de origem destacada (observe que está destacada no pacote decodificado, bem como o dump hexadecimal na parte inferior):

Wireshark mostrando um pacote TCP SYN

derobert
fonte
> Obrigado pela explicação. Então, você quis dizer que o novo descritor de soquete do servidor (ou seja, tupla) obtido após a aceitação () terá os detalhes da porta e do endereço do cliente e o uso desse novo servidor de descritor de soquete está enviando e recebendo os dados para O novo descritor de arquivo de soquete terá um novo número de porta de servidor atribuído pelo kernel, ip do servidor, ip do cliente e porta do cliente.
Subi Suresh
@SubiSuresh sim, a tupla é armazenada dentro do kernel, associada ao descritor de arquivo.
Derobert
> Obrigado derobert. Então, estou concluindo que o novo descritor de soquete do servidor terá a porta e o endereço do cliente, que o servidor obtém do accept (). Meu entendimento está correto, certo?
Subi Suresh
@SubiSuresh Sim, está correto. Do ponto de vista do aplicativo, você geralmente não se importa (exceto para o log). O kernel garante que os dados que você write(etc.) vão para o lugar certo.
Derobert
> obrigado por sua ajuda e acho que entendi. ;-)
Subi Suresh
2

A "solicitação de conexão ( connect()normalmente, a chamada do sistema do programa cliente ) causa um handshake de três vias . O primeiro pacote do handshake de três vias (do cliente para o servidor) tem o sinalizador SYN definido e inclui o número da porta TCP que o programa cliente kernel atribui a ele.

Você pode ver isso em um artigo sobre pacotes Nmap vs Natural SYN . A decodificação de pacotes Nmap SYN possui a frase "source.60058> dest.22". A decodificação "legítimo pacote SYN" contém a frase "source.35970> dest.80". Os dois pacotes SYN informam ao kernel remoto que os pacotes são da porta TCP 60058 e da porta 35970, respectivamente.

Bruce Ediger
fonte
> Mas Bruce que está acontecendo no end.But volta como o meu servidor é realmente buscar os detalhes como número de porta becuase normalmente em programas de servidor cliente, eu nunca vi qualquer função para pegar porta do cliente e endereço do cliente
Subi Suresh
A chamada do sistema getpeername()deve permitir que você faça isso em qualquer soquete aberto. A accept()chamada do sistema que o código do servidor deve usar para obter um descritor de arquivo de soquete para se comunicar com o cliente possui um parâmetro ("sockaddr" nas minhas páginas de manual) que contém o endereço IP e o número da porta TCP do cliente em potencial.
Edith Bruce # 7/13
De todas as entradas que entendi que o accept () está tendo a estrutura sockaddr_in preenchida com detalhes do cliente e o novo descritor de soquete do servidor retornado após o accept () terá automaticamente a porta e o endereço do cliente. É por isso que somos capazes de enviar usando send (novo descritor de soquete do servidor) .Espero que esteja certo? Isso é apenas para garantir que o que eu entendi esteja certo.
Subi Suresh
@SubiSuresh - Eu acredito que você escreveu a verdade.
Edith Bruce #
1

O soquete TCP é um soquete orientado para o fluxo. Os dois descritores de soquete (pertencentes a você e seu par) estão conectados de maneira confiável. Então você não precisa se preocupar com a porta do cliente - basta escrever o seu descritor de soquete!

Além disso, sinta-se à vontade para o getsockname (2) se você realmente quiser saber (talvez para registrar).

b166er
fonte
0

A conexão é definida por uma tupla (IP de origem, porta de origem, IP de destino, porta de destino). As respostas vão ao contrário.

vonbrand
fonte
@vondrand Esse ponto eu entendi von .Mas de qual função o servidor chega a saber sobre o número da porta do cliente? Sem saber o número da porta do cliente como ele será enviado.Então, o servidor usa a estrutura em accept () para buscar o cliente porta?
Subi Suresh