É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, disons que vous avez un serveur Web sur le port 80. Supposons que votre ordinateur a l'adresse IP publique 24.14.181.229 et que la personne qui essaie de se connecter à vous a l'adresse IP 10.1.2.3. Cette personne peut se connecter à vous en ouvrant une socket TCP vers 24.14.181.229:80. Assez simple.
Intuitivement (et à tort), la plupart des gens supposent que cela ressemble à quelque chose comme 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 à IP: PORT. Puisque le client se connecte au port 80, alors son port doit être 80 aussi? C'est une chose sensée à penser, mais en fait pas ce qui se passe. Si cela était correct, 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 du port 80 au port 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 obtient 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 par les 5 tuples suivants: (IP local, port local, IP distant, port distant, protocole). Si un élément du tuple est différent, il s'agit d'une connexion complètement indépendante.
3.) Lorsqu'un client se connecte à un serveur, il choisit un port source aléatoire et 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
Regard sur 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 (car tout un tas de choses se passe sur le port 80 car c'est un port commun, mais fonctionnellement 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 la sortie 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 -
Alors maintenant, il y a un processus qui écoute activement (état: LISTEN) sur le port 500. L'adresse locale est 0.0.0.0, qui est le code pour "écouter toutes les adresses IP". Une erreur facile à faire est d'écouter uniquement 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 () au port IP, et que ce processus est responsable de gérer toutes les connexions à ce port. Cela indique la limitation qu'il ne peut y avoir qu'un seul processus par ordinateur en écoute sur un port (il existe des moyens de contourner cela 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.
Alors 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 un socket TCP, envoie la charge utile ("Test payload." Dans ce cas), attend quelques secondes et se déconnecte. Faire à nouveau 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 refaites 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.