Pregunta

Quiero conseguir cualquier puerto TCP abierto al azar en el servidor local en Python. Lo que es la manera más fácil?

¿Fue útil?

Solución

Mi solución actual:

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

No es muy agradable y no es 100% correcto, pero funciona por ahora.

Otros consejos

El puerto libre se puede encontrar mediante la unión de un zócalo para un puerto seleccionado por el sistema operativo. Después de que el sistema operativo selecciona un puerto de la toma de corriente puede estar dispuesto. Sin embargo, esta solución no es resistente a las condiciones de carrera -. En el corto tiempo entre conseguir el número de puerto libre y el uso de este puerto otro proceso puede utilizar este puerto

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.

En realidad, haga lo siguiente en uno de mis programas:

port = random.randint(10000,60000)

Por supuesto, esto es aún más propenso a las colisiones que el código que tiene. Pero nunca he tenido un problema con él. El punto es que, en un momento dado, la mayoría de los puertos de numeración alta no están en uso y si usted acaba de elegir uno al azar, teniendo un conflicto con otro proceso es bastante improbable. Si haces algo como la solución que usted ha escrito en su respuesta (la apertura de una toma de corriente y el acaparamiento de su número de puerto), es casi seguro que el puerto no va a conflictos. Así que si esto es algo que sólo se va a utilizar por sí mismo (en oposición a algo que va a liberar al público), pensar si vale la pena dar con una solución verdaderamente a prueba de balas. Lo más probable es que nunca va a hacer la diferencia.

Motivado por el comentario Marcelo Cantos' en su pregunta, voy a añadir que la solución estándar en casos como este es hacer que el proceso que se va a utilizar el enlace de puerto a él y luego compartir esa información con cualquier otro programa que lo necesite . Normalmente se hará algo como escribir un archivo temporal que contiene el número de puerto a algún lugar en el sistema de archivos estándar. Dado que el proceso que está trabajando no hace eso, en cierto sentido, cualquier solución que ocurrió con la voluntad de ser un poco de un truco. Pero, de nuevo, si es sólo para su propio uso, eso es probablemente muy bien.

Esta es mi versión, sin embargo, no es realmente aleatoria si se especifica un rango de puertos. Esto también sufren de condiciones de carrera, pero esta es la mejor manera que sé si lo que necesita saber el puerto antes de tiempo.

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')

Los puertos efímeros básicamente se encuentran en el rango de 49152 a 65535. Si desea comprobar los puertos en el rango más grande que acaba de cambiar los valores en 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top