Sur localhost, comment choisir un numéro de port gratuit?

161

J'essaie de jouer avec la communication inter-processus et comme je ne pouvais pas comprendre comment utiliser des tuyaux nommés sous Windows, j'ai pensé que j'utiliserais des sockets réseau. Tout se passe localement. Le serveur est capable de lancer des esclaves dans un processus séparé et écoute sur certains ports. Les esclaves font leur travail et soumettent le résultat au maître. Comment déterminer quel port est disponible? Je suppose que je ne peux pas écouter sur le port 80 ou 21?

J'utilise Python, si cela réduit les choix.

Merci!

Anton L.
la source
1
Incidemment, si vous choisissez simplement un numéro de port aléatoire ou aléatoire (de préférence supérieur à 1024), il sera probablement disponible. Vous pouvez même utiliser le port 80 ou 21 ou autre, tant qu'aucun autre programme n'est à l'écoute. À tout moment, sur un système normal, seule une petite fraction des ports est utilisée.
David Z le
19
Choisir un port aléatoire n'est pas une bonne idée - laissez le système d'exploitation en choisir un pour vous.
Corehpf
Sur POSIX: stackoverflow.com/questions/913501/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

225

Ne vous liez pas à un port spécifique, ni au port 0, par exemple sock.bind(('', 0)). Le système d'exploitation choisira alors un port disponible pour vous. Vous pouvez obtenir le port choisi en utilisant sock.getsockname()[1]et le transmettre aux esclaves afin qu'ils puissent se reconnecter.

mark4o
la source
4
Voir stackoverflow.com/a/2838309/3538289 pour un exemple desock.bind(('',0))
cevaris
10
Comment transmettez-vous le numéro aux esclaves? Cela me semble être un problème de poule et d'œuf.
Sebastian
2
Si les esclaves sont créés après la liaison, vous pouvez simplement le passer en paramètre lors de leur création. Vous pouvez également l'écrire dans une mémoire partagée ou dans un fichier auquel les deux peuvent accéder, ou un serveur central auquel on accède via un numéro de port bien connu pourrait en garder une trace.
mark4o
49

Par souci d'extrait de ce que les gars ont expliqué ci-dessus:

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
la source
3
si sur localhost: c'est peut s.bind(('localhost', 0))- être mieux
codeskyblue
3
Il est également bon d'ajouter ce qui suit afin que vous puissiez réutiliser rapidement ce port avant votre déclaration de retour:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird
1
@jonEbird Est-ce socket.SO_REUSEADDRvraiment utile dans ce cas? D'après ce que j'ai lu, il est seulement pertinent que le socket qui essaie de se lier a SO_REUSEADDRet peu importe si cet indicateur est défini sur le socket persistant.
Karl Bartel le
41

Liez le socket au port 0. Un port libre aléatoire de 1024 à 65535 sera sélectionné. Vous pouvez récupérer le port sélectionné getsockname()juste après bind().

Havenard
la source
2

Vous pouvez écouter sur le port de votre choix; généralement, les applications utilisateur doivent écouter les ports 1024 et plus (via 65535). L'essentiel si vous avez un nombre variable d'écouteurs est d'allouer une plage à votre application - disons 20000-21000, et CATCH EXCEPTIONS . C'est ainsi que vous saurez si un port est inutilisable (utilisé par un autre processus, en d'autres termes) sur votre ordinateur.

Cependant, dans votre cas, vous ne devriez pas avoir de problème en utilisant un seul port codé en dur pour votre écouteur, tant que vous imprimez un message d'erreur si la liaison échoue.

Notez également que la plupart de vos sockets (pour les esclaves) n'ont pas besoin d'être explicitement liées à des numéros de port spécifiques - seules les sockets qui attendent des connexions entrantes (comme votre maître ici) devront être un écouteur et liés à un port. Si un port n'est pas spécifié pour un socket avant son utilisation, le système d'exploitation attribuera un port utilisable au socket. Lorsque le maître veut répondre à un esclave qui lui envoie des données, l'adresse de l'expéditeur est accessible lorsque l'auditeur reçoit des données.

Je suppose que vous utiliserez UDP pour cela?

Walt W
la source
0

Si vous avez seulement besoin de trouver un port libre pour une utilisation ultérieure, voici un extrait de code similaire à une réponse précédente , mais plus court, en utilisant socketserver :

import socketserver

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

Notez que le port n'est pas garanti pour rester libre, vous devrez donc peut-être placer cet extrait et le code qui l'utilise dans une boucle.

Mihai Capotă
la source