Dans la programmation de socket, vous créez un socket d'écoute, puis pour chaque client qui se connecte, vous obtenez un socket de flux normal que vous pouvez utiliser pour gérer la demande du client. Le système d'exploitation gère la file d'attente des connexions entrantes dans les coulisses.
Deux processus ne peuvent pas se lier au même port en même temps - par défaut, de toute façon.
Je me demande s'il existe un moyen (sur n'importe quel système d'exploitation connu, en particulier Windows) de lancer plusieurs instances d'un processus, de sorte qu'elles se lient toutes au socket et qu'elles partagent ainsi efficacement la file d'attente. Chaque instance de processus pourrait alors être à un seul thread; il bloquerait simplement lors de l'acceptation d'une nouvelle connexion. Lorsqu'un client se connectait, l'une des instances de processus inactives accepterait ce client.
Cela permettrait à chaque processus d'avoir une implémentation très simple, à un seul thread, ne partageant rien sauf via une mémoire partagée explicite, et l'utilisateur serait en mesure d'ajuster la bande passante de traitement en démarrant plus d'instances.
Une telle fonctionnalité existe-t-elle?
Edit: Pour ceux qui demandent "Pourquoi ne pas utiliser les threads?" Les threads sont évidemment une option. Mais avec plusieurs threads dans un seul processus, tous les objets peuvent être partagés et il faut veiller à ce que les objets ne soient pas partagés, ou ne soient visibles que par un thread à la fois, ou soient absolument immuables, et les langages les plus populaires et Les runtimes n'ont pas de support intégré pour gérer cette complexité.
En démarrant une poignée de processus de travail identiques, vous obtiendrez un système simultané dans lequel la valeur par défaut est pas de partage, ce qui facilite grandement la création d'une implémentation correcte et évolutive.
la source
Réponses:
Vous pouvez partager une socket entre deux (ou plus) processus sous Linux et même Windows.
Sous Linux (ou OS de type POSIX), utiliser
fork()
fera que l'enfant forké aura des copies de tous les descripteurs de fichiers du parent. Tout ce qu'il ne ferme pas continuera à être partagé et (par exemple avec un socket d'écoute TCP) pourra être utilisé pour deaccept()
nouvelles sockets pour les clients. C'est le nombre de serveurs, y compris Apache dans la plupart des cas, qui fonctionnent.Sous Windows, la même chose est fondamentalement vraie, sauf qu'il n'y
fork()
a pas d' appel système, donc le processus parent devra utiliserCreateProcess
ou quelque chose pour créer un processus enfant (qui peut bien sûr utiliser le même exécutable) et doit lui passer un handle héritable.Faire d'un socket d'écoute un handle héritable n'est pas une activité complètement triviale mais pas trop délicate non plus.
DuplicateHandle()
doit être utilisé pour créer un handle en double (toujours dans le processus parent), sur lequel l'indicateur héritable sera défini. Ensuite , vous pouvez donner cette poignée dans laSTARTUPINFO
structure du processus d'enfant dans CreateProcess commeSTDIN
,OUT
ou laERR
poignée ( en supposant que vous ne voulez pas l' utiliser pour quoi que ce soit d' autre).ÉDITER:
En lisant la bibliothèque MDSN, il semble que ce
WSADuplicateSocket
soit un mécanisme plus robuste ou correct pour ce faire; ce n'est toujours pas trivial car les processus parent / enfant doivent déterminer quel handle doit être dupliqué par un mécanisme IPC (bien que cela puisse être aussi simple qu'un fichier dans le système de fichiers)CLARIFICATION:
En réponse à la question initiale du PO, non, plusieurs processus ne le peuvent pas
bind()
; juste le processus parent d' origine appelleraitbind()
,listen()
etc., les processus enfants seraient tout simplement traiter les demandes paraccept()
,send()
,recv()
etc.la source
La plupart des autres ont fourni les raisons techniques pour lesquelles cela fonctionne. Voici un code python que vous pouvez exécuter pour le démontrer par vous-même:
Notez qu'il y a en effet deux processus à l'écoute:
Voici les résultats de l'exécution de telnet et du programme:
la source
Je voudrais ajouter que les sockets peuvent être partagées sous Unix / Linux via les sockets AF__UNIX (sockets inter-processus). Ce qui semble se produire, c'est qu'un nouveau descripteur de socket est créé qui est en quelque sorte un alias de l'original. Ce nouveau descripteur de socket est envoyé via le socket AFUNIX à l'autre processus. Ceci est particulièrement utile dans les cas où un processus ne peut pas fork () pour partager ses descripteurs de fichiers. Par exemple, lors de l'utilisation de bibliothèques qui empêchent cela en raison de problèmes de thread. Vous devez créer une socket de domaine Unix et utiliser libancillary pour envoyer le descripteur.
Voir:
Pour créer des sockets AF_UNIX:
Par exemple de code:
la source
On dirait que cette question a déjà reçu une réponse complète de MarkR et zackthehack, mais je voudrais ajouter que Nginx est un exemple du modèle d'héritage de socket d'écoute.
Voici une bonne description:
la source
Je ne sais pas dans quelle mesure cela est pertinent pour la question d'origine, mais dans le noyau Linux 3.9, il existe un correctif ajoutant une fonctionnalité TCP / UDP: prise en charge de TCP et UDP pour l'option de socket SO_REUSEPORT; La nouvelle option de socket permet à plusieurs sockets sur le même hôte de se lier au même port et vise à améliorer les performances des applications de serveur de réseau multithread s'exécutant sur des systèmes multicœurs. plus d'informations peuvent être trouvées dans le lien LWN SO_REUSEPORT dans Linux Kernel 3.9 comme mentionné dans le lien de référence:
l'option SO_REUSEPORT n'est pas standard, mais disponible sous une forme similaire sur un certain nombre d'autres systèmes UNIX (notamment les BSD, d'où l'idée est née). Il semble offrir une alternative utile pour tirer le maximum des performances des applications réseau exécutées sur des systèmes multicœurs, sans avoir à utiliser le modèle fork.
la source
SO_REUSEPORT
créer un pool de threads, où chaque socket est sur un thread différent mais un seul socket du groupe effectue leaccept
. Pouvez-vous confirmer que toutes les prises du groupe reçoivent chacune une copie des données?À partir de Linux 3.9, vous pouvez définir SO_REUSEPORT sur un socket puis faire partager ce socket à plusieurs processus non liés. C'est plus simple que le schéma prefork, plus de problèmes de signal, de fuite fd vers les processus enfants, etc.
Linux 3.9 a introduit une nouvelle façon d'écrire des serveurs socket
L'option de socket SO_REUSEPORT
la source
Ayez une seule tâche dont le seul travail est d'écouter les connexions entrantes. Lorsqu'une connexion est reçue, il accepte la connexion - cela crée un descripteur de socket distinct. Le socket accepté est passé à l'une de vos tâches de travail disponibles et la tâche principale revient à l'écoute.
la source
Sous Windows (et Linux), il est possible pour un processus d'ouvrir une socket puis de la passer à un autre processus de sorte que ce second processus puisse également utiliser cette socket (et la transmettre à son tour, s'il le souhaite) .
L'appel de fonction crucial est WSADuplicateSocket ().
Cela remplit une structure avec des informations sur un socket existant. Cette structure ensuite, via un mécanisme IPC de votre choix, est passée à un autre processus existant (notez que je dis existant - lorsque vous appelez WSADuplicateSocket (), vous devez indiquer le processus cible qui recevra les informations émises).
Le processus de réception peut alors appeler WSASocket (), en passant cette structure d'informations, et recevoir un handle vers le socket sous-jacent.
Les deux processus détiennent désormais un handle vers le même socket sous-jacent.
la source
Cela ressemble à ce que vous voulez, c'est qu'un processus écoute de nouveaux clients, puis transfère la connexion une fois que vous avez une connexion. Faire cela à travers les threads est facile et dans .Net vous avez même les méthodes BeginAccept etc. pour vous occuper d'une grande partie de la plomberie. Transférer les connexions au-delà des limites du processus serait compliqué et n'aurait aucun avantage en termes de performances.
Vous pouvez également avoir plusieurs processus liés et en écoute sur le même socket.
Si vous lancez deux processus exécutant chacun le code ci-dessus, cela fonctionnera et le premier processus semble obtenir toutes les connexions. Si le premier processus est tué, le second obtient alors les connexions. Avec un partage de socket comme celui-ci, je ne sais pas exactement comment Windows décide quel processus obtient de nouvelles connexions, bien que le test rapide indique que le processus le plus ancien les obtient en premier. Quant à savoir s'il partage si le premier processus est occupé ou quelque chose comme ça, je ne sais pas.
la source
Une autre approche (qui évite de nombreux détails complexes) dans Windows si vous utilisez HTTP, consiste à utiliser HTTP.SYS . Cela permet à plusieurs processus d'écouter différentes URL sur le même port. Sur le serveur 2003/2008 / Vista / 7, c'est ainsi que fonctionne IIS, vous pouvez donc partager des ports avec lui. (Sur XP SP2, HTTP.SYS est pris en charge, mais IIS5.1 ne l'utilise pas.)
D'autres API de haut niveau (y compris WCF) utilisent HTTP.SYS.
la source