web-dev-qa-db-fra.com

TCP: deux sockets différents peuvent-ils partager un port?

C'est peut-être une question très fondamentale, mais cela me trouble.

Deux sockets connectés différents peuvent-ils partager un port? J'écris un serveur d'applications capable de gérer plus de 100 000 connexions simultanées, et nous savons que le nombre de ports disponibles sur un système est d'environ 60 000 (16 bits). Une socket connectée est affectée à un nouveau port (dédié), ce qui signifie que le nombre de connexions simultanées est limité par le nombre de ports, à moins que plusieurs sockets ne puissent partager le même port. Alors la question.

Merci pour l'aide à l'avance!

89
K J

Un socket serveur écoute sur un seul port. Toutes les connexions client établies sur ce serveur sont associées au même port d'écoute côté serveur de la connexion. Une connexion établie est identifiée de manière unique par la combinaison de paires IP/Port côté client et côté serveur. Plusieurs connexions sur le même serveur peuvent partager la même paire côté serveur IP/Port tant qu'elles sont associées à différentes côté client paires IP/Port, et le - serveur serait capable de gérer autant de clients que le permettent les ressources système disponibles.

Sur le côté client, il est courant que les nouvelles connexions sortantes utilisent un port aléatoire côté client, auquel cas il est possible de manquer de ports disponibles si vous établissez beaucoup de liens en peu de temps.

126
Remy Lebeau

Écoute TCP/HTTP sur les ports: Comment plusieurs utilisateurs peuvent-ils partager le même port?

Alors, que se passe-t-il lorsqu'un serveur écoute les connexions entrantes sur un port TCP? Par exemple, supposons que vous disposiez d'un serveur Web sur le port 80. Supposons que votre ordinateur dispose de l'adresse IP publique sur 24.14.181.229 et la personne qui tente de se connecter à vous a l'adresse IP 10.1.2.3 Cette personne peut se connecter à vous en ouvrant un TCP socket à 24.14.181.229:80. Assez simple.

Intuitivement (et à tort), la plupart des gens supposent que cela ressemble à ceci:

    Local Computer    | Remote Computer
    --------------------------------
    <local_ip>:80     | <foreign_ip>:80

    ^^ not actually what happens, but this is the conceptual model a lot of people have in mind.

C'est intuitif, car du point de vue du client, il a une adresse IP et se connecte à un serveur à l'adresse IP: PORT. Puisque le client se connecte au port 80, son port doit être également 80? C'est une chose sensée à penser, mais en réalité pas ce qui se passe. Si cela devait être correct, nous ne pourrions servir qu'un seul utilisateur par adresse IP étrangère. Une fois qu'un ordinateur distant est connecté, il connecte les ports 80 à 80 et personne d'autre ne peut se connecter.

Trois choses doivent être comprises:

1.) Sur un serveur, un processus écoute sur un port. Une fois qu'il est connecté, il passe à un autre thread. La communication ne cache jamais le port d'écoute.

2.) Les connexions sont identifiées de manière unique par le système d’exploitation par le 5-Tuple suivant: (IP local, port local, IP distant, port distant, protocole). Si l'un des éléments du tuple est différent, il s'agit d'une connexion totalement indépendante.

3.) Lorsqu'un client se connecte à un serveur, il choisit un port source aléatoire inutilisé . De cette façon, un seul client peut avoir jusqu'à 64 000 connexions au serveur pour le même port de destination.

Donc, c'est vraiment ce qui est créé lorsqu'un client se connecte à un serveur:

    Local Computer   | Remote Computer           | Role
    -----------------------------------------------------------
    0.0.0.0:80       | <none>                    | LISTENING
    127.0.0.1:80     | 10.1.2.3:<random_port>    | ESTABLISHED

Regarder ce qui se passe réellement

Tout d’abord, utilisons netstat pour voir ce qui se passe sur cet ordinateur. Nous allons utiliser le port 500 au lieu de 80 (parce que tout un tas de choses se passent sur le port 80 car c'est un port commun, mais sur le plan fonctionnel, cela ne fait aucune différence).

    netstat -atnp | grep -i ":500 "

Comme prévu, la sortie est vide. Maintenant, démarrons un serveur web:

    Sudo python3 -m http.server 500

Maintenant, voici le résultat de l'exécution de netstat à nouveau:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      - 

Il existe donc à présent un processus à l'écoute active (State: LISTEN) sur le port 500. L'adresse locale est 0.0.0.0, qui correspond au code "écoute de toutes les adresses ip". Une erreur facile à faire est de n'écouter que sur le port 127.0.0.1, qui n'acceptera que les connexions de l'ordinateur actuel. Donc, ce n'est pas une connexion, cela signifie simplement qu'un processus a demandé à bind () de porter l'adresse IP, et que ce processus est responsable du traitement de toutes les connexions à ce port. Cela laisse à penser qu'il ne peut y avoir qu'un seul processus par ordinateur qui écoute sur un port (il existe des moyens de contourner ce problème en utilisant le multiplexage, mais le sujet est beaucoup plus compliqué). Si un serveur Web écoute sur le port 80, il ne peut pas partager ce port avec d'autres serveurs Web.

Alors maintenant, connectons un utilisateur à notre machine:

    quicknet -m tcp -t localhost:500 -p Test payload.

C’est un script simple ( https://github.com/grokit/quickweb ) qui ouvre un TCP socket, envoie la charge utile ("Test payload." Dans Dans ce cas, attend quelques secondes et déconnecte. Réactiver netstat pendant que cela se produit affiche les éléments suivants:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:54240      ESTABLISHED -

Si vous vous connectez avec un autre client et effectuez à nouveau netstat, vous verrez ce qui suit:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:26813      ESTABLISHED -

... c'est-à-dire que le client a utilisé un autre port aléatoire pour la connexion. Donc, il n'y a jamais de confusion entre les adresses IP.

115
N0thing

Une prise connectée est affectée à un nouveau port (dédié)

C'est une intuition commune, mais c'est inexact. Une prise connectée n'est pas affectée à un nouveau port/dédié. La seule contrainte réelle à laquelle doit satisfaire la pile TCP est que le tuple de (adresse_local, adresse_local, adresse_distant, port_distant) doit être unique pour chaque connexion de socket. Ainsi, le serveur peut avoir de nombreux TCP sockets utilisant le même port local, à condition que chacun des sockets du port soit connecté à un emplacement distant différent.

Voir le paragraphe "Socket Pair" à: http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20Tuple&pg=PA52#v=onepage&q=socket% 20pair% 20Tuple & f = false

27
Jeremy Friesner

Théoriquement oui. Pratique, pas. La plupart des noyaux (y compris linux) ne vous permettent pas un second bind() sur un port déjà alloué. Ce n'était pas vraiment un gros patch pour permettre cela.

Sur le plan conceptuel, nous devrions différencier socket et port. Les sockets sont des points de terminaison de la communication bidirectionnelle, c’est-à-dire des "choses" où nous pouvons envoyer et recevoir des octets. C'est une chose de conception, il n'y a pas de tel champ dans un en-tête de paquet nommé "socket".

Port est un identifiant capable d'identifier un socket. Dans le cas du protocole TCP, un port est un entier de 16 bits, mais il existe également d'autres protocoles (par exemple, sur les sockets unix, un "port" est essentiellement une chaîne).

Le problème principal est le suivant: si un paquet entrant arrive, le noyau peut identifier son socket par son numéro de port de destination. C'est un moyen très courant, mais ce n'est pas la seule possibilité:

  • Les sockets peuvent être identifiés par l'adresse IP de destination des paquets entrants. C'est le cas, par exemple, si nous avons un serveur utilisant deux adresses IP simultanément. Ensuite, nous pouvons exécuter, par exemple, différents serveurs Web sur les mêmes ports, mais sur des adresses IP différentes.
  • Les sockets peuvent être identifiés par leur source port et ip. C'est le cas dans de nombreuses configurations d'équilibrage de charge.

Parce que vous travaillez sur un serveur d'applications, il sera capable de le faire.

7
peterh