Comment le serveur sait-il à quel port client envoyer?

26

Si je comprends bien, c'est ce qui se passe lorsqu'un client fait une demande de connexion:

  1. Le serveur sera lié à un numéro de port particulier. Le numéro de port est toujours lié à un processus d'écoute. Étant donné que seul le serveur écoute les connexions entrantes, nous n'avons pas besoin de lier du côté client
  2. Le serveur continuera à écouter ce numéro de port.
  3. Le client enverra une connect()demande.
  4. Le serveur acceptera la demande en utilisant accept(). Dès que le serveur accepte la demande du client, le noyau alloue un numéro de port aléatoire pour le serveur pour plus loin send()et receive(), puisque le même numéro de port sur le serveur ne peut pas être utilisé pour l'envoi et l'écoute, et le port précédent est toujours écouter de nouvelles connexions

Compte tenu de tout cela, comment le serveur peut-il savoir sur quel port le client reçoit? Je sais que le client enverra des segments TCP avec un port source et un port de destination, donc le serveur utilisera le port source de ce segment comme port de destination, mais quelle fonction le serveur appelle-t-il pour connaître ce port? C'est ça accept()?

Subi Suresh
la source

Réponses:

33

Cela fait partie de l'en-tête TCP (ou UDP, etc.), dans le paquet. Le serveur le découvre donc parce que le client le lui dit. Ceci est similaire à la façon dont il découvre l'adresse IP du client (qui fait partie de l'en-tête IP).

Par exemple, chaque paquet TCP comprend un en-tête IP (avec au moins l'IP source, l'IP de destination et le protocole [TCP]). Ensuite, il y a un en-tête TCP (avec les ports source et de destination, et plus encore).

Lorsque le noyau reçoit un paquet SYN (le début d'une connexion TCP) avec une IP distante de 10.11.12.13 (dans l'en-tête IP) et un port distant de 12345 (dans l'en-tête TCP), il connaît alors l'IP et le port distants . Il renvoie un SYN | ACK. S'il obtient un ACK en retour, l' listenappel renvoie un nouveau socket, configuré pour cette connexion.

Un socket TCP est identifié de manière unique par les quatre valeurs (IP distante, IP locale, port distant, port local). Vous pouvez avoir plusieurs connexions / sockets, à condition qu'au moins l'une d'entre elles diffère.

En règle générale, le port local et l'IP locale seront les mêmes pour toutes les connexions à un processus serveur (par exemple, toutes les connexions à sshd seront sur local-ip: 22). Si une machine distante établit plusieurs connexions, chacune utilisera un port distant différent. Donc, tout sauf le port distant sera le même, mais ça va, un seul des quatre doit différer.

Vous pouvez utiliser, par exemple, wirehsark pour voir le paquet, et il étiquetera toutes les données pour vous. Voici le port source mis en évidence (notez-le mis en évidence dans le paquet décodé, ainsi que le vidage hexadécimal en bas):

Wireshark montrant un paquet TCP SYN

derobert
la source
> Merci pour l'explication. Donc, vous vouliez dire que le nouveau descripteur de socket de serveur (c'est-à-dire le tuple) obtenu après accept () aura le port client et les informations d'adresse client et utiliser ce nouveau serveur de descripteur de socket pour envoyer et recevoir les données à et à partir du client. Un nouveau descripteur de fichier socket aura un nouveau numéro de port de serveur attribué par le noyau, l'IP du serveur, l'IP du client et le port client.
Subi Suresh
@SubiSuresh oui, le tuple est stocké dans le noyau, associé à ce descripteur de fichier.
derobert
> Merci derobert. Je conclus donc que le nouveau descripteur de socket de serveur aura le port client et l'adresse client, que le serveur obtient de accept (). Ma compréhension est très bien non?
Subi Suresh
@SubiSuresh Oui, c'est exact. Du point de vue de l'application, vous ne vous souciez généralement pas (sauf pour la journalisation). Le noyau s'assure que les données que vous write(etc.) allez au bon endroit.
derobert
> merci pour votre aide et je pense avoir compris. ;-)
Subi Suresh
2

La "demande de connexion (l' connect()appel système du programme client , généralement) provoque une négociation à trois voies . Le premier paquet de la négociation à trois voies (du client au serveur) a l'indicateur SYN défini et inclut le numéro de port TCP du programme client. le noyau lui assigne.

Vous pouvez le voir dans un article sur les paquets Nmap vs Natural SYN . Le décodage de paquets Nmap SYN a la phrase "source.60058> dest.22". Le décodage "paquet SYN légitime" contient la phrase "source.35970> dest.80". Les deux paquets SYN indiquent au noyau distant que les paquets proviennent respectivement du port TCP 60058 et du port 35970.

Bruce Ediger
la source
> Mais Bruce cela se produit dans le back-end. Mais comment mon serveur récupère réellement les détails comme le numéro de port parce que normalement dans les programmes serveur client, je n'ai jamais vu de fonction pour récupérer le port client et l'adresse client
Subi Suresh
L'appel système getpeername()devrait vous permettre de le faire sur n'importe quel socket ouvert. L' accept()appel système que le code serveur doit utiliser pour obtenir un descripteur de fichier socket pour communiquer avec le client a un paramètre ("sockaddr" dans mes pages de manuel) qui contient l'adresse IP du client potentiel et le numéro de port TCP.
Bruce Ediger
> S'il vous plaît ne me dérange pas si j'obtiens. De toutes les entrées que j'ai reçues, j'ai compris que accept () a la structure sockaddr_in remplie avec les détails du client et le nouveau descripteur de socket du serveur retourné après accept () aura automatiquement le port et l'adresse du client. C'est pourquoi nous pouvons envoyer en utilisant send (nouveau descripteur de socket de serveur) .J'espère, suis-je au point? C'est juste pour m'assurer que ce que j'ai compris est juste.
Subi Suresh
@SubiSuresh - Je crois que vous avez écrit la vérité.
Bruce Ediger
1

Le socket TCP est un socket orienté flux. Les deux descripteurs de socket (détenus par vous et votre homologue) sont connectés de manière fiable. Vous n'avez donc pas à vous soucier du port client - écrivez simplement votre descripteur de socket!

Aussi, n'hésitez pas à getsockname (2) si vous voulez vraiment le savoir (pour vous connecter peut-être).

b166er
la source
0

La connexion est définie par un tuple (IP source, port source, IP de destination, port de destination). Les réponses vont dans le sens inverse.

vonbrand
la source
@vondrand Ce point que j'ai compris von .Mais à partir de quelle fonction le serveur vient-il de connaître le numéro de port client? Sans connaître le numéro de port client comment il sera envoyé. Port ?
Subi Suresh