L'API socket est la norme de facto pour les communications TCP / IP et UDP / IP (c'est-à-dire le code réseau tel que nous le connaissons). Cependant, l'une de ses fonctions essentielles accept()
est un peu magique.
Pour emprunter une définition semi-formelle:
accept () est utilisé côté serveur. Il accepte une tentative entrante de créer une nouvelle connexion TCP à partir du client distant et crée un nouveau socket associé à la paire d'adresses de socket de cette connexion.
En d'autres termes, accept
renvoie un nouveau socket via lequel le serveur peut communiquer avec le client nouvellement connecté. L'ancienne socket (sur laquelle accept
on a appelé) reste ouverte, sur le même port, à l'écoute des nouvelles connexions.
Comment ça accept
marche? Comment est-il mis en œuvre? Il y a beaucoup de confusion sur ce sujet. De nombreuses personnes prétendent accepter d'ouvrir un nouveau port et que vous communiquez avec le client via celui-ci. Mais ce n'est évidemment pas vrai, car aucun nouveau port n'est ouvert. Vous pouvez en fait communiquer via le même port avec différents clients, mais comment? Lorsque plusieurs threads appellent recv
sur le même port, comment les données savent-elles où aller?
Je suppose que c'est quelque chose du genre que l'adresse du client est associée à un descripteur de socket, et chaque fois que des données arrivent, recv
elles sont acheminées vers la bonne socket, mais je ne suis pas sûr.
Ce serait formidable d'obtenir une explication approfondie du fonctionnement interne de ce mécanisme.
la source
Réponses:
Votre confusion réside dans le fait qu'une socket est identifiée par Server IP: Server Port. En réalité, les sockets sont identifiés de manière unique par un quatuor d'informations:
Client IP : Client Port
etServer IP : Server Port
Ainsi, alors que l'adresse IP du serveur et le port du serveur sont constants dans toutes les connexions acceptées, les informations côté client sont ce qui lui permet de suivre où tout se passe.
Exemple pour clarifier les choses:
Disons que nous avons un serveur à
192.168.1.1:80
et deux clients,10.0.0.1
et10.0.0.2
.10.0.0.1
ouvre une connexion sur le port local1234
et se connecte au serveur. Maintenant, le serveur a un socket identifié comme suit:10.0.0.2
Ouvre maintenant une connexion sur le port local5678
et se connecte au serveur. Maintenant, le serveur a deux sockets identifiés comme suit:la source
Juste pour ajouter à la réponse donnée par l'utilisateur "17 sur 26"
Le socket se compose en fait de 5 tuple - (adresse IP source, port source, adresse IP de destination, port de destination, protocole). Ici, le protocole pourrait TCP ou UDP ou tout autre protocole de couche de transport. Ce protocole est identifié dans le paquet à partir du champ «protocole» du datagramme IP.
Ainsi, il est possible d'avoir des applications différentes sur le serveur communiquant avec le même client sur exactement les mêmes 4-uplets mais différents dans le domaine du protocole. Par exemple
Apache côté serveur parlant sur (server1.com:880-client1:1234 sur TCP) et World of Warcraft parlant sur (server1.com:880-client1:1234 sur UDP)
Le client et le serveur traiteront ceci comme le champ de protocole dans le paquet IP dans les deux cas est différent même si tous les 4 autres champs sont identiques.
la source
Ce qui m'a dérouté lorsque j'apprenais cela, c'est que les termes
socket
etport
suggèrent qu'ils sont quelque chose de physique, alors qu'en fait ce ne sont que des structures de données que le noyau utilise pour résumer les détails du réseau.En tant que telles, les structures de données sont implémentées pour pouvoir séparer les connexions de différents clients. Quant à la façon dont ils sont mis en œuvre, la réponse est soit a.) Cela n'a pas d'importance, le but de l'API sockets est précisément que l'implémentation ne devrait pas avoir d'importance ou b.) Il suffit de regarder. Outre les livres Stevens hautement recommandés fournissant une description détaillée d'une implémentation, consultez la source sous Linux ou Solaris ou l'un des BSD.
la source
Comme l'a dit l'autre gars, une socket est identifiée de manière unique par un 4-tuple (IP client, port client, IP serveur, port serveur).
Le processus serveur en cours d'exécution sur l'IP du serveur maintient une base de données (ce qui signifie que je ne me soucie pas du type de structure de données table / liste / arbre / tableau / magie qu'il utilise) de sockets actives et écoute sur le port du serveur. Lorsqu'il reçoit un message (via la pile TCP / IP du serveur), il vérifie l'adresse IP et le port du client par rapport à la base de données. Si l'adresse IP du client et le port client se trouvent dans une entrée de base de données, le message est transmis à un gestionnaire existant, sinon une nouvelle entrée de base de données est créée et un nouveau gestionnaire est généré pour gérer ce socket.
Dans les premiers jours de l'ARPAnet, certains protocoles (FTP pour un) écoutaient un port spécifié pour les demandes de connexion et répondaient avec un port de transfert. D'autres communications pour cette connexion passeraient par le port de transfert. Cela a été fait pour améliorer les performances par paquet: les ordinateurs étaient plusieurs ordres de grandeur plus lents à l'époque.
la source