Question

Je veux obtenir un port TCP aléatoire ouvert sur localhost en Python. Quelle est la meilleure façon?

Était-ce utile?

La solution

Ma solution actuelle:

def get_open_port():
        import socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("",0))
        s.listen(1)
        port = s.getsockname()[1]
        s.close()
        return port

Pas très agréable et pas non plus 100% correct, mais cela fonctionne pour l'instant.

Autres conseils

Le port libre peut être trouvé en se liant d'une prise à un port sélectionné par le système d'exploitation. Une fois le système d'exploitation sélectionne un port de la prise de courant peut être disposé. Cependant, cette solution ne résiste pas aux conditions de course -. Dans le temps entre l'obtention du numéro de port gratuit et en utilisant ce port autre processus peut utiliser ce port

def find_free_port():
    s = socket.socket()
    s.bind(('', 0))            # Bind to a free port provided by the host.
    return s.getsockname()[1]  # Return the port number assigned.

J'utilise en fait ce qui suit dans l'un de mes programmes:

port = random.randint(10000,60000)

Bien sûr, cela est encore plus sujette à des collisions que le code que vous avez. Mais je ne l'ai jamais eu un problème avec elle. Le point est, à un moment donné, la plupart de ces ports numérotés de haut ne sont pas utilisés et si vous venez de choisir un au hasard, d'avoir un conflit avec un autre processus est assez peu probable. Si vous faites quelque chose comme la solution que vous avez publié dans votre réponse (une socket et saisissant son numéro de port), il est presque certain que le port ne va pas au conflit. Donc, si cela est quelque chose que vous n'utiliser pour vous-même (par opposition à quelque chose que vous allez libérer au public), pensez à savoir si cela vaut la peine de venir avec une solution vraiment l'épreuve des balles. Les chances sont qu'il ne fera jamais changer les choses.

Motivé par le commentaire de Marcelo Cantos sur votre question, je vais ajouter que la solution standard dans les cas comme celui-ci est d'avoir le processus qui utilisera la liaison du port et ensuite partager cette information avec tout autre programme dont il a besoin . En général, il fera quelque chose comme écrire un fichier temporaire contenant le numéro de port à un emplacement standard dans le système de fichiers. Le processus que vous travaillez avec ne le fait pas, en quelque sens que ce soit la solution que vous venez avec sera un peu un hack. Mais encore une fois, si elle est juste pour votre propre usage, c'est probablement très bien.

Ceci est ma version, mais son si vous spécifiez pas vraiment au hasard une plage de ports. Cela souffrent également de conditions de course, mais c'est la meilleure façon que je sais si vous avez besoin de savoir à l'avance le port.

import socket
import errno
import contextlib

reserved_ports = set()

def get_open_port(lowest_port = 0, highest_port = None, bind_address = '', *socket_args, **socket_kwargs):
    if highest_port is None:
        highest_port = lowest_port + 100
    while lowest_port < highest_port:
        if lowest_port not in reserved_ports:
            try:
                with contextlib.closing(socket.socket(*socket_args, **socket_kwargs)) as my_socket:
                    my_socket.bind((bind_address, lowest_port))
                    this_port = my_socket.getsockname()[1]
                    reserved_ports.add(this_port)
                    return this_port
            except socket.error as error:
                if not error.errno == errno.EADDRINUSE:
                    raise
                assert not lowest_port == 0
                reserved_ports.add(lowest_port)
        lowest_port += 1
    raise Exception('Could not find open port')

Les ports éphémères se situent essentiellement dans la gamme 49152-65535. si vous voulez vérifier les ports dans une plus grande plage puis juste changer les valeurs randint.

import pustil
from random import randint
def getfreeport():
    port = randint(49152,65535)
    portsinuse=[]
    while True:
        conns = pstuil.net_connections()
        for conn in conns:
            portsinuse.append(con.laddr[1])
        if port in portsinuse:
            port = randint(49152,65535)
        else:
            break
    return port
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top