TCP: Können sich zwei verschiedene Sockets einen Port teilen?


124

Dies mag eine sehr grundlegende Frage sein, aber sie verwirrt mich.

Können sich zwei verschiedene angeschlossene Sockets einen Port teilen? Ich schreibe einen Anwendungsserver, der mehr als 100.000 gleichzeitige Verbindungen verarbeiten kann, und wir wissen, dass die Anzahl der auf einem System verfügbaren Ports etwa 60.000 (16 Bit) beträgt. Ein verbundener Socket wird einem neuen (dedizierten) Port zugewiesen. Dies bedeutet, dass die Anzahl der gleichzeitigen Verbindungen durch die Anzahl der Ports begrenzt ist, es sei denn, mehrere Sockets können denselben Port gemeinsam nutzen. Also die Frage.

Vielen Dank für die Hilfe im Voraus!

Antworten:


175

Ein Server- Socket überwacht einen einzelnen Port. Alle auf diesem Server hergestellten Clientverbindungen sind auf der Serverseite der Verbindung demselben Überwachungsport zugeordnet . Eine hergestellte Verbindung wird durch die Kombination von clientseitigen und serverseitigen IP / Port-Paaren eindeutig identifiziert. Mehrere Verbindungen auf demselben Server können dasselbe serverseitige IP / Port-Paar gemeinsam nutzen, sofern sie verschiedenen clientseitigen IP / Port-Paaren und dem Server zugeordnet sind kann so viele Clients verarbeiten, wie es die verfügbaren Systemressourcen zulassen zu.

Auf der Clientseite ist es üblich, dass neue ausgehende Verbindungen einen zufälligen clientseitigen Port verwenden. In diesem Fall können die verfügbaren Ports ausgehen, wenn Sie in kurzer Zeit viele Verbindungen herstellen.


2
Danke für die Antwort, Remy! Ihre Antwort ist alles, worauf ich neugierig war. ;)
KJ

2
@Remy-Verbindungen werden nicht nur nach Quell- / Zielport / IP, sondern auch nach einem Protokoll (TCP, UDP usw.) unterschieden, wenn ich mich nicht irre.
Ondrej Peterka

1
@OndraPeterka: Ja, aber nicht alle Plattformen beschränken dies. Beispielsweise lässt Windows zu, dass separate IPv4- und IPv6-Server-Sockets denselben lokalen IP: Port abhören, ohne durch die Rahmen zu springen, * Nix-Systeme (einschließlich Linux und Android) jedoch nicht.
Remy Lebeau

6
@ user2268997: Sie können nicht einen einzelnen Socket verwenden, um eine Verbindung zu mehreren Servern herzustellen. Sie müssen für jede Verbindung einen separaten Socket erstellen.
Remy Lebeau

3
@FernandoGonzalezSanchez: Ein einzelner Client kann mehrere TCP-Sockets haben, die an dasselbe lokale IP / Port-Paar gebunden sind, solange sie mit verschiedenen Remote-IP / Port-Paaren verbunden sind. Das ist nicht spezifisch für Windows, das ist ein Teil der Funktionsweise von TCP im Allgemeinen.
Remy Lebeau

182

TCP / HTTP-Überwachung von Ports: Wie können viele Benutzer denselben Port gemeinsam nutzen?

Was passiert also, wenn ein Server an einem TCP-Port auf eingehende Verbindungen wartet? Angenommen, Sie haben einen Webserver an Port 80. Nehmen wir an, Ihr Computer hat die öffentliche IP-Adresse 24.14.181.229 und die Person, die versucht, eine Verbindung zu Ihnen herzustellen, hat die IP-Adresse 10.1.2.3. Diese Person kann eine Verbindung zu Ihnen herstellen, indem sie einen TCP-Socket bis 24.14.181.229:80 öffnet. Einfach genug.

Intuitiv (und fälschlicherweise) gehen die meisten Leute davon aus, dass es ungefähr so ​​aussieht:

    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.

Dies ist intuitiv, da er aus Sicht des Clients eine IP-Adresse hat und unter IP: PORT eine Verbindung zu einem Server herstellt. Da der Client eine Verbindung zu Port 80 herstellt, muss sein Port auch 80 sein? Dies ist eine vernünftige Sache zu denken, aber eigentlich nicht, was passiert. Wenn das richtig wäre, könnten wir nur einen Benutzer pro fremder IP-Adresse bedienen. Sobald ein Remotecomputer eine Verbindung hergestellt hat, würde er die Verbindung von Port 80 zu Port 80 blockieren, und niemand anderes könnte eine Verbindung herstellen.

Drei Dinge müssen verstanden werden:

1.) Auf einem Server lauscht ein Prozess auf einem Port. Sobald eine Verbindung hergestellt wurde, wird sie an einen anderen Thread übergeben. Die Kommunikation belastet niemals den Abhörport.

2.) Verbindungen werden vom Betriebssystem durch das folgende 5-Tupel eindeutig identifiziert: (lokale IP, lokaler Port, Remote-IP, Remote-Port, Protokoll). Wenn ein Element im Tupel anders ist, ist dies eine völlig unabhängige Verbindung.

3.) Wenn ein Client eine Verbindung zu einem Server herstellt, wählt er einen zufälligen, nicht verwendeten Quellport höherer Ordnung aus . Auf diese Weise kann ein einzelner Client für denselben Zielport bis zu ~ 64.000 Verbindungen zum Server haben.

Das wird also wirklich erstellt, wenn ein Client eine Verbindung zu einem Server herstellt:

    Local Computer   | Remote Computer           | Role
    -----------------------------------------------------------
    0.0.0.0:80       | <none>                    | LISTENING
    127.0.0.1:80     | 10.1.2.3:<random_port>    | ESTABLISHED

Betrachten, was tatsächlich passiert

Lassen Sie uns zunächst netstat verwenden, um zu sehen, was auf diesem Computer geschieht. Wir werden Port 500 anstelle von 80 verwenden (da auf Port 80 eine ganze Reihe von Dingen passiert, da es sich um einen gemeinsamen Port handelt, aber funktional macht es keinen Unterschied).

    netstat -atnp | grep -i ":500 "

Wie erwartet ist die Ausgabe leer. Starten wir nun einen Webserver:

    sudo python3 -m http.server 500

Hier ist die Ausgabe von netstat:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      - 

Jetzt gibt es einen Prozess, der aktiv auf Port 500 lauscht (Status: LISTEN). Die lokale Adresse lautet 0.0.0.0. Dies ist der Code für "Lauschen auf alle IP-Adressen". Ein leichter Fehler besteht darin, nur Port 127.0.0.1 abzuhören, der nur Verbindungen vom aktuellen Computer akzeptiert. Dies ist also keine Verbindung. Dies bedeutet lediglich, dass ein Prozess zum Binden () an Port-IP angefordert wird und dieser Prozess für die Verarbeitung aller Verbindungen zu diesem Port verantwortlich ist. Dies weist auf die Einschränkung hin, dass es nur einen Prozess pro Computer geben kann, der einen Port überwacht (es gibt Möglichkeiten, dies mithilfe von Multiplexing zu umgehen, dies ist jedoch ein viel komplizierteres Thema). Wenn ein Webserver Port 80 überwacht, kann er diesen Port nicht für andere Webserver freigeben.

Lassen Sie uns nun einen Benutzer mit unserer Maschine verbinden:

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

Dies ist ein einfaches Skript ( https://github.com/grokit/quickweb ), das einen TCP-Socket öffnet, die Nutzdaten sendet (in diesem Fall "Nutzdaten testen"), einige Sekunden wartet und die Verbindung trennt. Wenn Sie netstat erneut ausführen, während dies geschieht, wird Folgendes angezeigt:

    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 -

Wenn Sie eine Verbindung mit einem anderen Client herstellen und netstat erneut ausführen, wird Folgendes angezeigt:

    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 -

... das heißt, der Client hat einen anderen zufälligen Port für die Verbindung verwendet. Es gibt also nie Verwechslungen zwischen den IP-Adressen.


11
Dies ist die beste Antwort, die ich je auf SO gesehen habe.
Jobs

1
@ N0thing "Auf diese Weise kann ein einzelner Client bis zu ~ 64.000 Verbindungen zum Server für denselben Zielport haben." Wenn ein Client in der Praxis nicht zweimal oder mehrmals gleichzeitig eine Verbindung zu demselben Server und Port herstellt, kann ein Client sogar mehr als ~ 64 KB Verbindungen haben. Ist das wahr. Wenn ja, bedeutet dies, dass von einem einzelnen Port auf der Clientseite aus eine Verbindung zu vielen verschiedenen Serverprozessen hergestellt werden kann (sodass die Socket-Verbindung unterschiedlich ist). Insgesamt können sich also mehrere Client-Sockets auf demselben Port auf dem Client-Computer befinden? Bitte lesen Sie meinen Kommentar zur Antwort "Remey Lebeau". Danke: D
Prem KTiw

6
@premktiw: Ja, mehrere Client-Sockets können gleichzeitig an dasselbe lokale IP / Port-Paar gebunden werden, wenn sie mit verschiedenen Server-IP / Port-Paaren verbunden sind, sodass die Tupel von lokalen + Remote-Paaren eindeutig sind. Und ja, es ist möglich, dass ein Client insgesamt mehr als 64.000 gleichzeitige Verbindungen hat. Von einem einzelnen Port aus kann eine Verbindung zu einer möglicherweise unendlichen Anzahl von Servern hergestellt werden (begrenzt durch verfügbare Betriebssystemressourcen, verfügbare Router-Ports usw.), solange die Server-IP / Port-Paare eindeutig sind.
Remy Lebeau

1
@RemyLebeau Zufrieden. Vielen Dank: D
Prem KTiw

1
@bibstha Wie geht die Firewall mit zufälligen Ports um, wenn alle eingehenden Verbindungen abgelehnt werden?
PatrykG

35

Ein angeschlossener Socket wird einem neuen (dedizierten) Port zugewiesen

Das ist eine verbreitete Intuition, aber falsch. Ein angeschlossener Socket ist keinem neuen / dedizierten Port zugeordnet. Die einzige tatsächliche Einschränkung, die der TCP-Stapel erfüllen muss, besteht darin, dass das Tupel (local_address, local_port, remote_address, remote_port) für jede Socket-Verbindung eindeutig sein muss. Somit kann der Server viele TCP-Sockets haben, die denselben lokalen Port verwenden, solange jeder der Sockets am Port mit einem anderen Remote-Standort verbunden ist.

Siehe den Abschnitt "Socket Pair" unter: http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20tuple&pg=PA52#v=onepage&q=socket%20pair%20tuple&f=false


1
Danke für die perfekte Antwort, Jeremy!
KJ

6
Was Sie sagen, gilt völlig für die Serverseite. Die Struktur der BSD Sockets-API bedeutet jedoch, dass ausgehende clientseitige Ports in der Praxis eindeutig sein müssen, da die bind()Operation der connect()Operation sogar implizit vorausgeht .
Marquis von Lorne

1
@EJP Hallo, dachte ich bind() wird nur auf der Serverseite verwendet, bevor accept()?also die Clientseite auch den jeweiligen Port bindet?
GMsoF

5
@GMsoF: bind()kann vorher auf der Client-Seite verwendet werden connect().
Remy Lebeau

10

Theoretisch ja. Übe nicht. Die meisten Kernel (inkl. Linux) erlauben Ihnen keine Sekunde bind()zu einem bereits zugewiesenen Port. Es war kein wirklich großer Patch, dies zuzulassen.

Konzeptionell sollten wir zwischen Socket und Port unterscheiden . Sockets sind bidirektionale Kommunikationsendpunkte, dh "Dinge", an denen wir Bytes senden und empfangen können. Es ist eine konzeptionelle Sache, es gibt kein solches Feld in einem Paket-Header mit dem Namen "Socket".

Port ist eine Kennung, die einen Socket identifizieren kann. Im Fall von TCP ist ein Port eine 16-Bit-Ganzzahl, es gibt jedoch auch andere Protokolle (bei Unix-Sockets ist ein "Port" im Wesentlichen eine Zeichenfolge).

Das Hauptproblem ist das Folgende: Wenn ein eingehendes Paket eintrifft, kann der Kernel seinen Socket anhand seiner Zielportnummer identifizieren. Dies ist der häufigste Weg, aber nicht die einzige:

  • Sockets können anhand der Ziel-IP der eingehenden Pakete identifiziert werden. Dies ist beispielsweise der Fall, wenn ein Server zwei IPs gleichzeitig verwendet. Dann können wir zum Beispiel verschiedene Webserver auf denselben Ports, aber auf verschiedenen IPs ausführen.
  • Steckdosen sind an ihren zu erkennen Quellports und ihrer IP- . Dies ist in vielen Lastausgleichskonfigurationen der Fall.

Da Sie an einem Anwendungsserver arbeiten, kann dieser dies tun.


2
Er fragte nicht nach einer Sekunde bind().
Marquis von Lorne

1
@ user207421 Haben Sie jemals ein Betriebssystem gesehen, bei dem keine Hörbuchsen eingerichtet sind bind()? Ich kann es mir vorstellen, ja, es ist durchaus möglich, aber Tatsache ist, dass sowohl WinSock als auch die Posix-API den bind()Aufruf dafür verwenden, selbst wenn ihre Parametrisierung praktisch gleich ist. Auch wenn eine API diesen Aufruf nicht hat, müssen Sie ihn irgendwie sagen, von wo aus Sie die eingehenden Bytes lesen möchten .
Peter - Wiedereinstellung Monica

1
@ user207421 Natürlich können 100.000 oder mehr TCP-Verbindungen mit denselben Ports verarbeitet werden. listen()/ accept()API-Aufrufe können die Sockets so erstellen, dass der Kernel sie durch ihre eingehenden Ports unterscheidet. Die Frage des OP kann so interpretiert werden, wie er es im Wesentlichen verlangt. Ich denke, es ist ziemlich realistisch, aber nicht das ist es, was seine Frage wörtlich bedeutet.
Peter

1

Nein. Es ist nicht möglich, denselben Port zu einem bestimmten Zeitpunkt gemeinsam zu nutzen. Sie können Ihre Anwendung jedoch so gestalten, dass der Portzugriff zu einem anderen Zeitpunkt erfolgt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.