Wie wähle ich auf localhost eine freie Portnummer aus?

160

Ich versuche, mit der Kommunikation zwischen Prozessen zu spielen, und da ich unter Windows nicht herausfinden konnte, wie Named Pipes verwendet werden, dachte ich, ich werde Netzwerk-Sockets verwenden. Alles passiert vor Ort. Der Server kann Slaves in einem separaten Prozess starten und überwacht einen Port. Die Sklaven erledigen ihre Arbeit und senden das Ergebnis an den Master. Wie finde ich heraus, welcher Port verfügbar ist? Ich nehme an, ich kann Port 80 oder 21 nicht abhören.

Ich benutze Python, wenn das die Auswahl einschränkt.

Vielen Dank!

Anton L.
quelle
1
Übrigens, wenn Sie nur eine zufällige oder zufällige Portnummer auswählen (vorzugsweise höher als 1024), ist diese wahrscheinlich verfügbar. Sie können sogar Port 80 oder 21 oder was auch immer verwenden, solange kein anderes Programm darauf lauscht. Zu einem bestimmten Zeitpunkt wird auf einem normalen System nur ein kleiner Teil der Ports verwendet.
David Z
19
Die Auswahl eines zufälligen Ports ist keine gute Idee - lassen Sie das Betriebssystem einen für Sie auswählen.
Corehpf
Auf POSIX: stackoverflow.com/questions/913501/…
Ciro Santilli 法轮功 冠状 病 六四 事件 19

Antworten:

224

Binden Sie nicht an einen bestimmten Port oder an Port 0, z sock.bind(('', 0)). Das Betriebssystem wählt dann einen verfügbaren Port für Sie aus. Sie können den ausgewählten Port abrufen sock.getsockname()[1]und an die Slaves weiterleiten, damit diese wieder eine Verbindung herstellen können.

mark4o
quelle
4
Siehe stackoverflow.com/a/2838309/3538289 für ein Beispielsock.bind(('',0))
cevaris
10
Wie geben Sie die Nummer an die Sklaven weiter? Klingt für mich nach einem Henne-Ei-Problem.
Sebastian
2
Wenn die Slaves nach dem Binden erstellt werden, können Sie sie beim Erstellen einfach als Parameter übergeben. Alternativ können Sie es in einen gemeinsam genutzten Speicher oder in eine Datei schreiben, auf die beide zugreifen können, oder ein zentraler Server, auf den über eine bekannte Portnummer zugegriffen wird, kann den Überblick behalten.
Mark4o
49

Zum Ausschnitt dessen, was die Jungs oben erklärt haben:

import socket
from contextlib import closing

def find_free_port():
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
        s.bind(('', 0))
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        return s.getsockname()[1]
saaj
quelle
3
wenn auf localhost: vielleicht s.bind(('localhost', 0))ist besser
Codeskyblue
3
Es ist auch gut, Folgendes hinzuzufügen, damit Sie diesen Port vor Ihrer Rückgabeanweisung schnell wiederverwenden können:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird
1
@jonEbird Hilft socket.SO_REUSEADDRin diesem Fall wirklich? Nach dem, was ich gelesen habe, ist es nur relevant, dass der Socket, der zu binden versucht, hat, SO_REUSEADDRund es ist irrelevant, ob dieses Flag auf dem verweilenden Socket gesetzt ist.
Karl Bartel
41

Binden Sie den Socket an Port 0. Ein zufälliger freier Port von 1024 bis 65535 wird ausgewählt. Sie können den ausgewählten Port mit getsockname()direkt danach abrufen bind().

Zufluchtsort
quelle
2

Sie können jeden gewünschten Port abhören. Im Allgemeinen sollten Benutzeranwendungen die Ports 1024 und höher (bis 65535) abhören. Wenn Sie eine variable Anzahl von Listenern haben, müssen Sie Ihrer App hauptsächlich einen Bereich zuweisen, z . B. 20000-21000 und CATCH EXCEPTIONS . Auf diese Weise wissen Sie, ob ein Port auf Ihrem Computer unbrauchbar ist (dh von einem anderen Prozess verwendet wird).

In Ihrem Fall sollten Sie jedoch kein Problem damit haben, einen einzelnen fest codierten Port für Ihren Listener zu verwenden, solange Sie eine Fehlermeldung drucken, wenn die Bindung fehlschlägt.

Beachten Sie auch, dass die meisten Ihrer Sockets (für die Slaves) nicht explizit an bestimmte Portnummern gebunden sein müssen - nur Sockets, die auf eingehende Verbindungen warten (wie Ihr Master hier), müssen zu einem Listener gemacht und an einen Port gebunden werden. Wenn für einen Socket vor seiner Verwendung kein Port angegeben wurde, weist das Betriebssystem dem Socket einen verwendbaren Port zu. Wenn der Master auf einen Slave antworten möchte, der ihm Daten sendet, ist die Adresse des Absenders zugänglich, wenn der Listener Daten empfängt.

Ich nehme an, Sie werden dafür UDP verwenden?

Walt W.
quelle
0

Wenn Sie nur einen freien Port für die spätere Verwendung suchen müssen, finden Sie hier einen Ausschnitt, der einer vorherigen Antwort ähnelt , jedoch mit socketserver kürzer ist :

import socketserver

with socketserver.TCPServer(("localhost", 0), None) as s:
    free_port = s.server_address[1]

Beachten Sie, dass nicht garantiert wird, dass der Port frei bleibt. Daher müssen Sie dieses Snippet und den Code, der es verwendet, möglicherweise in eine Schleife einfügen.

Mihai Capotă
quelle