Bei der Socket-Programmierung erstellen Sie einen Listening-Socket und erhalten dann für jeden Client, der eine Verbindung herstellt, einen normalen Stream-Socket, mit dem Sie die Client-Anforderung bearbeiten können. Das Betriebssystem verwaltet die Warteschlange eingehender Verbindungen hinter den Kulissen.
Zwei Prozesse können nicht gleichzeitig an denselben Port gebunden werden - jedenfalls standardmäßig.
Ich frage mich, ob es eine Möglichkeit gibt (unter einem bekannten Betriebssystem, insbesondere Windows), mehrere Instanzen eines Prozesses zu starten, sodass sie alle an den Socket gebunden sind und die Warteschlange effektiv gemeinsam nutzen. Jede Prozessinstanz könnte dann ein einzelner Thread sein. es würde nur blockieren, wenn eine neue Verbindung akzeptiert wird. Wenn ein Client verbunden ist, akzeptiert eine der inaktiven Prozessinstanzen diesen Client.
Dies würde es jedem Prozess ermöglichen, eine sehr einfache Single-Threaded-Implementierung zu haben, die nichts gemeinsam nutzt, außer durch expliziten gemeinsamen Speicher, und der Benutzer könnte die Verarbeitungsbandbreite anpassen, indem er mehr Instanzen startet.
Gibt es eine solche Funktion?
Bearbeiten: Für diejenigen, die fragen "Warum nicht Threads verwenden?" Offensichtlich sind Threads eine Option. Bei mehreren Threads in einem einzigen Prozess sind jedoch alle Objekte gemeinsam nutzbar, und es muss sorgfältig darauf geachtet werden, dass Objekte entweder nicht gemeinsam genutzt werden oder nur für jeweils einen Thread sichtbar sind oder absolut unveränderlich sind und die beliebtesten Sprachen und Sprachen verwenden Die Laufzeiten bieten keine integrierte Unterstützung für die Verwaltung dieser Komplexität.
Wenn Sie eine Handvoll identischer Worker-Prozesse starten, erhalten Sie ein gleichzeitiges System, in dem standardmäßig keine Freigabe erfolgt, was das Erstellen einer korrekten und skalierbaren Implementierung erheblich vereinfacht.
quelle
Antworten:
Sie können einen Socket zwischen zwei (oder mehr) Prozessen unter Linux und sogar Windows gemeinsam nutzen.
Unter Linux (oder Betriebssystem vom Typ POSIX) führt die Verwendung
fork()
dazu, dass das gegabelte Kind Kopien aller Dateideskriptoren des Elternteils hat. Alles, was nicht geschlossen wird, wird weiterhin freigegeben und kann (z. B. mit einem TCP-Listening-Socket) füraccept()
neue Sockets für Clients verwendet werden. So viele Server, in den meisten Fällen einschließlich Apache, funktionieren.Unter Windows gilt im Grunde das Gleiche, außer dass es keinen
fork()
Systemaufruf gibt, sodass der übergeordnete ProzessCreateProcess
einen untergeordneten Prozess (der natürlich dieselbe ausführbare Datei verwenden kann) oder etwas anderes verwenden muss und ihm ein vererbbares Handle übergeben muss.Einen Listening-Socket zu einem vererbbaren Handle zu machen, ist keine völlig triviale Aktivität, aber auch nicht zu schwierig.
DuplicateHandle()
muss verwendet werden, um ein doppeltes Handle zu erstellen (das sich jedoch noch im übergeordneten Prozess befindet), auf dem das vererbbare Flag gesetzt ist. Dann können Sie diesen Griff in die gebenSTARTUPINFO
Struktur , um das Kind Prozess in Createprocess als eineSTDIN
,OUT
oderERR
Griff (vorausgesetzt , Sie wollten es nicht für irgendetwas anderes verwenden).BEARBEITEN:
Beim Lesen der MDSN-Bibliothek scheint dies
WSADuplicateSocket
ein robusterer oder korrekterer Mechanismus zu sein. Es ist immer noch nicht trivial, da die übergeordneten / untergeordneten Prozesse herausfinden müssen, welches Handle von einem IPC-Mechanismus dupliziert werden muss (obwohl dies so einfach sein kann wie eine Datei im Dateisystem).KLÄRUNG:
Als Antwort auf die ursprüngliche Frage des OP können mehrere Prozesse nicht
bind()
; nur der ursprünglichen Eltern - Prozess nennen würdebind()
,listen()
usw., würden die Child - Prozesse nur Anfragen verarbeiten durchaccept()
,send()
,recv()
usw.quelle
Die meisten anderen haben die technischen Gründe angegeben, warum dies funktioniert. Hier ist ein Python-Code, den Sie ausführen können, um dies selbst zu demonstrieren:
Beachten Sie, dass tatsächlich zwei Prozess-IDs abhören:
Hier sind die Ergebnisse von Telnet und dem Programm:
quelle
Ich möchte hinzufügen, dass die Sockets unter Unix / Linux über AF__UNIX-Sockets (Interprozess-Sockets) gemeinsam genutzt werden können. Was zu passieren scheint, ist, dass ein neuer Socket-Deskriptor erstellt wird, der in gewisser Weise ein Alias zum ursprünglichen ist. Dieser neue Socket-Deskriptor wird über den AFUNIX-Socket an den anderen Prozess gesendet. Dies ist besonders nützlich, wenn ein Prozess seine Dateideskriptoren nicht mit fork () teilen kann. Zum Beispiel, wenn Bibliotheken verwendet werden, die dies aufgrund von Threading-Problemen verhindern. Sie sollten einen Unix-Domain-Socket erstellen und libancillary verwenden , um den Deskriptor zu senden.
Sehen:
So erstellen Sie AF_UNIX-Sockets:
Zum Beispiel Code:
quelle
Diese Frage wurde anscheinend bereits vollständig von MarkR und zackthehack beantwortet, aber ich möchte hinzufügen, dass Nginx ein Beispiel für das Listening-Socket-Vererbungsmodell ist.
Hier ist eine gute Beschreibung:
quelle
Ich bin mir nicht sicher, wie relevant dies für die ursprüngliche Frage ist, aber im Linux-Kernel 3.9 gibt es einen Patch, der eine TCP / UDP-Funktion hinzufügt: TCP- und UDP-Unterstützung für die SO_REUSEPORT-Socket-Option; Die neue Socket-Option ermöglicht die Bindung mehrerer Sockets auf demselben Host an denselben Port und soll die Leistung von Multithread-Netzwerkserveranwendungen verbessern, die auf Multicore-Systemen ausgeführt werden. Weitere Informationen finden Sie im LWN-Link LWN SO_REUSEPORT in Linux Kernel 3.9, wie im Referenzlink angegeben:
Die Option SO_REUSEPORT ist nicht Standard, steht jedoch in ähnlicher Form auf einer Reihe anderer UNIX-Systeme zur Verfügung (insbesondere auf den BSDs, aus denen die Idee stammt). Es scheint eine nützliche Alternative zu sein, um die maximale Leistung von Netzwerkanwendungen, die auf Multicore-Systemen ausgeführt werden, zu nutzen, ohne das Gabelmuster verwenden zu müssen.
quelle
SO_REUSEPORT
ein Thread-Pool erstellt wird, in dem sich jeder Socket in einem anderen Thread befindet, aber nur ein Socket in der Gruppe das ausführtaccept
. Können Sie bestätigen, dass alle Sockets in der Gruppe jeweils eine Kopie der Daten erhalten?Ab Linux 3.9 können Sie SO_REUSEPORT für einen Socket festlegen und dann mehrere nicht verwandte Prozesse diesen Socket gemeinsam nutzen. Das ist einfacher als das Prefork-Schema, keine Signalprobleme mehr, kein Leck an untergeordnete Prozesse usw.
Linux 3.9 führte eine neue Methode zum Schreiben von Socket-Servern ein
Die Socket-Option SO_REUSEPORT
quelle
Haben Sie eine einzige Aufgabe, deren einzige Aufgabe es ist, auf eingehende Verbindungen zu warten. Wenn eine Verbindung empfangen wird, akzeptiert sie die Verbindung. Dadurch wird ein separater Socket-Deskriptor erstellt. Der akzeptierte Socket wird an eine Ihrer verfügbaren Worker-Aufgaben übergeben, und die Hauptaufgabe wird wieder abgehört.
quelle
Unter Windows (und Linux) ist es möglich, dass ein Prozess einen Socket öffnet und diesen Socket dann an einen anderen Prozess weitergibt, sodass dieser zweite Prozess diesen Socket ebenfalls verwenden kann (und ihn nacheinander weitergibt, falls er dies wünscht). .
Der entscheidende Funktionsaufruf ist WSADuplicateSocket ().
Dadurch wird eine Struktur mit Informationen zu einem vorhandenen Socket gefüllt. Diese Struktur wird dann über einen IPC-Mechanismus Ihrer Wahl an einen anderen vorhandenen Prozess übergeben (ich sage vorhanden - wenn Sie WSADuplicateSocket () aufrufen, müssen Sie den Zielprozess angeben, der die ausgegebenen Informationen erhält).
Der empfangende Prozess kann dann WSASocket () aufrufen, diese Informationsstruktur übergeben und ein Handle an den zugrunde liegenden Socket empfangen.
Beide Prozesse halten jetzt ein Handle für denselben zugrunde liegenden Socket.
quelle
Es hört sich so an, als ob Sie einen Prozess wünschen, der auf neue Clients wartet und die Verbindung dann abgibt, sobald Sie eine Verbindung erhalten. Dies über Threads hinweg zu tun ist einfach und in .Net haben Sie sogar die BeginAccept usw. Methoden, um einen Großteil der Installation für Sie zu erledigen. Das Übergeben der Verbindungen über Prozessgrenzen hinweg wäre kompliziert und hätte keine Leistungsvorteile.
Alternativ können Sie mehrere Prozesse an denselben Socket binden und abhören.
Wenn Sie zwei Prozesse starten, die jeweils den obigen Code ausführen, funktioniert dies und der erste Prozess scheint alle Verbindungen zu erhalten. Wenn der erste Prozess beendet wird, erhält der zweite die Verbindungen. Bei einer solchen Socket-Freigabe bin ich mir nicht sicher, wie Windows genau entscheidet, welcher Prozess neue Verbindungen erhält, obwohl der Schnelltest darauf hinweist, dass der älteste Prozess diese zuerst erhält. Ob es teilt, ob der erste Prozess beschäftigt ist oder so etwas, weiß ich nicht.
quelle
Ein anderer Ansatz (der viele komplexe Details vermeidet) in Windows, wenn Sie HTTP verwenden, ist die Verwendung von HTTP.SYS . Auf diese Weise können mehrere Prozesse unterschiedliche URLs am selben Port abhören. Unter Server 2003/2008 / Vista / 7 funktioniert IIS so, sodass Sie Ports für IIS freigeben können. (Unter XP SP2 wird HTTP.SYS unterstützt, IIS5.1 verwendet es jedoch nicht.)
Andere High-Level-APIs (einschließlich WCF) verwenden HTTP.SYS.
quelle