202 votes

TCP : deux sockets différentes peuvent-elles partager un port ?

Il s'agit peut-être d'une question très élémentaire, mais elle me perturbe.

Deux sockets différents peuvent-ils partager un port ? J'écris un serveur d'application qui devrait être capable de gérer plus de 100k connexions simultanées, et nous savons que le nombre de ports disponibles sur un système est d'environ 60k (16bit). Une socket connectée est assigné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 puissent partager le même port. La question est donc la suivante.

319voto

N0thing Points 94

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

Que se passe-t-il donc lorsqu'un serveur écoute les connexions entrantes sur un port TCP ? Par exemple, disons que vous avez un serveur web sur le port 80. Supposons que votre ordinateur ait l'adresse IP publique 24.14.181.229 et que la personne qui tente de se connecter à vous ait l'adresse IP 10.1.2.3. Cette personne peut se connecter à vous en ouvrant une socket TCP vers 24.14.181.229:80. C'est assez simple.

Intuitivement (et à tort), la plupart des gens pensent qu'il 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 également être 80 ? C'est une idée raisonnable, mais ce n'est pas ce qui se passe. Si c'était le cas, nous ne pourrions servir qu'un seul utilisateur par adresse IP étrangère. Une fois qu'un ordinateur distant se connecte, il monopolise la connexion entre le port 80 et le port 80, et personne d'autre ne peut se connecter.

Il faut comprendre trois choses :

1.) Sur un serveur, un processus est l'écoute sur un port. Une fois qu'il a obtenu une connexion, il la transmet à un autre thread. La communication ne monopolise jamais le port d'écoute.

2.) Les connexions sont identifiées de manière unique par le système d'exploitation au moyen du 5-tuple suivant : (local-IP, local-port, remote-IP, remote-port, 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 et inutilisé d'ordre supérieur . De cette façon, un seul client peut avoir jusqu'à ~64k connexions au serveur pour le même port de destination.

C'est donc 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 utiliserons 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 courant, mais fonctionnellement, cela ne fait pas de différence).

    netstat -atnp | grep -i ":500 "

Comme prévu, la sortie est vide. Démarrons maintenant un serveur web :

    sudo python3 -m http.server 500

Voici maintenant 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 y a donc maintenant un processus qui écoute activement (State : LISTEN) sur le port 500. L'adresse locale est 0.0.0.0, ce qui signifie "écoute de toutes les adresses IP". Une erreur facile à commettre est de n'écouter que sur le port 127.0.0.1, qui n'acceptera que les connexions provenant de l'ordinateur actuel. Il ne s'agit donc pas d'une connexion, cela signifie simplement qu'un processus a demandé à bind() sur le port IP, et que ce processus est responsable de la gestion de toutes les connexions sur ce port. Cela renvoie à la limitation selon laquelle il ne peut y avoir qu'un seul processus par ordinateur écoutant sur un port (il existe des moyens de contourner ce problème en utilisant le multiplexage, mais c'est un sujet beaucoup plus compliqué). Si un serveur web écoute sur le port 80, il ne peut pas partager ce port avec d'autres serveurs web.

Maintenant, connectons un utilisateur à notre machine :

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

Il s'agit d'un simple script ( https://github.com/grokit/quickweb ) qui ouvre une socket TCP, envoie la charge utile ("Test payload." dans ce cas), attend quelques secondes et se déconnecte. Si l'on refait netstat pendant que cela se produit, on obtient le résultat suivant :

    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 que vous exécutez à 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. Il n'y a donc jamais de confusion entre les adresses IP.

255voto

Remy Lebeau Points 130112

A serveur écoute sur un seul port. Toutes les connexions client établies sur ce serveur sont associées à ce même port d'écoute du côté du serveur de la connexion. Une connexion établie est identifiée de manière unique par la combinaison des paires IP/Port côté client et côté serveur. Plusieurs connexions sur le même serveur peuvent partager le même côté serveur La paire IP/Port doit être associée à des adresses IP/Port différentes. côté client Les paires IP/Port, et les serveur serait en mesure de gérer autant de clients que les ressources disponibles du système le lui permettent.

Sur le site côté client il est courant que les nouvelles connexions sortantes utilisent un numéro d'identification aléatoire. côté client Dans ce cas, il est possible de se retrouver à court de ports disponibles si l'on effectue un grand nombre de connexions en peu de temps.

57voto

Jeremy Friesner Points 16684

Un socket connecté est assigné à un nouveau port (dédié)

C'est une intuition courante, mais elle est erronée. Une socket connectée n'est pas assignée à un port nouveau/dédié. La seule contrainte réelle à laquelle la pile TCP doit satisfaire est que le tuple (adresse_locale, port_local, adresse_distante, port_distante) doit être unique pour chaque connexion de socket. Ainsi, le serveur peut avoir de nombreuses sockets TCP utilisant le même port local, à condition que chacune des sockets sur le port soit connectée à un emplacement distant différent.

Voir le paragraphe "Socket Pair" dans le livre "UNIX Network Programming : The sockets networking API" par W. Richard Stevens, Bill Fenner, Andrew M. Rudoff : http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20tuple&pg=PA52#v=onepage&q=socket%20pair%20tuple&f=false

13voto

Peter Horvath Points 2177

En théorie, oui. En pratique, non. La plupart des noyaux (y compris linux) n'autorisent pas une deuxième bind() à un port déjà attribué. Il n'y a pas eu de gros correctifs à apporter pour que cela soit autorisé.

D'un point de vue conceptuel, nous devrions faire la distinction entre prise y port . Les sockets sont des points d'extrémité de communication bidirectionnelle, c'est-à-dire des "choses" où l'on peut envoyer et recevoir des octets. Il s'agit d'une chose conceptuelle, il n'y a pas de champ nommé "socket" dans l'en-tête d'un paquet.

Le port est un identifiant qui permet d'identifier un socket. Dans le cas de TCP, un port est un entier de 16 bits, mais il existe aussi d'autres protocoles (par exemple, sur les sockets Unix, un "port" est essentiellement une chaîne de caractères).

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

  • Les sockets peuvent être identifiées par l'adresse IP de destination des paquets entrants. C'est le cas, par exemple, si nous avons un serveur qui utilise deux IP simultanément. Nous pouvons alors faire fonctionner, par exemple, différents serveurs web sur les mêmes ports, mais sur des IP différentes.
  • Les sockets peuvent être identifiées par leur source port et ip également. C'est le cas dans de nombreuses configurations d'équilibrage de charge.

Comme vous travaillez sur un serveur d'application, il sera en mesure de le faire.

3voto

JCKödel Points 173

Je suppose qu'aucun d'entre eux n'a

C

  1. I

  2. W

  3. T

  4. T

  5. W

  6. A

S

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X