En localhost, ¿cómo elijo un número de puerto libre?

161

Estoy tratando de jugar con la comunicación entre procesos y, dado que no pude encontrar la manera de usar tuberías con nombre en Windows, pensé que usaría sockets de red. Todo sucede a nivel local. El servidor puede lanzar esclavos en un proceso separado y escucha en algún puerto. Los esclavos hacen su trabajo y presentan el resultado al maestro. ¿Cómo averiguo qué puerto está disponible? ¿Asumo que no puedo escuchar en el puerto 80 o 21?

Estoy usando Python, si eso reduce las opciones.

¡Gracias!

Anton L.
fuente
1
Por cierto, si solo elige un número de puerto aleatorio o aleatorio (preferiblemente superior a 1024), probablemente estará disponible. Incluso puede usar el puerto 80 o 21 o lo que sea, siempre que ningún otro programa lo escuche. En un momento dado, en un sistema normal, solo se utiliza una pequeña fracción de los puertos.
David Z
19
Elegir un puerto aleatorio no es una buena idea: deje que el sistema operativo elija uno por usted.
Corehpf
En POSIX: stackoverflow.com/questions/913501/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

225

No se una a un puerto específico, ni a un puerto 0, por ejemplo sock.bind(('', 0)). El sistema operativo elegirá un puerto disponible para usted. Puede obtener el puerto elegido utilizando sock.getsockname()[1]y pasarlo a los esclavos para que puedan conectarse de nuevo.

mark4o
fuente
44
Consulte stackoverflow.com/a/2838309/3538289 para ver un ejemplo desock.bind(('',0))
cevaris el
10
¿Cómo se pasa el número a los esclavos? A mí me parece un problema de huevo y gallina.
Sebastian
2
Si los esclavos se crean después del enlace, puede pasarlo como un parámetro al crearlos. Alternativamente, podría escribirlo en alguna memoria compartida o en un archivo al que ambos puedan acceder, o un servidor central al que se acceda a través de algún número de puerto conocido podría realizar un seguimiento.
mark4o
49

En aras de un fragmento de lo que los chicos han explicado anteriormente:

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
fuente
3
si en localhost: tal vez s.bind(('localhost', 0))es mejor
codeskyblue
3
También es bueno agregar lo siguiente para que pueda reutilizar rápidamente ese puerto antes de su declaración de devolución:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird
1
@jonEbird ¿ socket.SO_REUSEADDRRealmente ayuda en este caso? Por lo que leí, solo es relevante que el zócalo que está tratando de vincularse tenga SO_REUSEADDRy es irrelevante si ese indicador está configurado en el zócalo persistente.
Karl Bartel
41

Enlace el zócalo al puerto 0. Se seleccionará un puerto libre aleatorio de 1024 a 65535. Puede recuperar el puerto seleccionado getsockname()inmediatamente después bind().

Havenard
fuente
2

Puede escuchar en cualquier puerto que desee; en general, las aplicaciones de usuario deben escuchar los puertos 1024 y superiores (hasta 65535). Lo principal si tiene un número variable de oyentes es asignar un rango a su aplicación, digamos 20000-21000, y EXCEPCIONES DE CAPTURAS . Así es como sabrá si un puerto no se puede usar (utilizado por otro proceso, en otras palabras) en su computadora.

Sin embargo, en su caso, no debería tener problemas al usar un solo puerto codificado para su escucha, siempre que imprima un mensaje de error si falla el enlace.

Tenga en cuenta también que la mayoría de sus sockets (para los esclavos) no necesitan estar vinculados explícitamente a números de puerto específicos; solo los sockets que esperan conexiones entrantes (como su maestro aquí) deberán hacerse escuchar y vincularse a un puerto. Si no se especifica un puerto para un socket antes de usarlo, el sistema operativo asignará un puerto utilizable al socket. Cuando el maestro quiere responder a un esclavo que le envía datos, la dirección del remitente es accesible cuando el oyente recibe datos.

¿Supongo que usarás UDP para esto?

Walt W
fuente
0

Si solo necesita encontrar un puerto libre para su uso posterior, aquí hay un fragmento similar a una respuesta anterior , pero más corto, usando el servidor de sockets :

import socketserver

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

Tenga en cuenta que no se garantiza que el puerto permanezca libre, por lo que es posible que deba colocar este fragmento y el código que lo usa en un bucle.

Mihai Capotă
fuente