2011-05-03 15 views
30

Tengo una aplicación de Python que abre un socket TCP simple para comunicarse con otra aplicación de Python en un host separado. A veces, el programa puede tener un error o lo mataré directamente, y en cualquier caso, el socket se puede dejar abierto durante un tiempo desconocido.¿Cómo cerrar un socket dejado abierto por un programa destruido?

La próxima vez que vaya a ejecutar el programa me sale este error:

socket.error: [Errno 98] Address already in use 

Ahora el programa siempre trata de utilizar el mismo puerto, por lo que parece como si todavía está abierta. Comprobé y estoy bastante seguro de que el programa no se está ejecutando en segundo plano y, sin embargo, mi dirección todavía está en uso.

SO, ¿cómo puedo cerrar manualmente (o de otra forma) un socket/dirección para que mi programa pueda volver a usarlo inmediatamente?

actualización

Sobre la base de la respuesta de Mike Revisé la página socket(7) y miré SO_REUSEADDR:

SO_REUSEADDR 
    Indicates that the rules used in validating addresses supplied in a bind(2) call should 
    allow reuse of local addresses. For AF_INET sockets this means that a socket may bind, 
    except when there is an active listening socket bound to the address. When the listen‐ 
    ing socket is bound to INADDR_ANY with a specific port then it is not possible to bind 
    to this port for any local address. Argument is an integer boolean flag. 
+0

¿Alguna oposición a mover esto a SO? Terminó siendo un problema completamente de programación, así que probablemente tiene más sentido allí –

+0

No, en absoluto, solo publiqué esto aquí porque estaba pensando en un comando de Linux para cerrar el socket, estoy de acuerdo con su material de programación. Quizás el título podría cambiarse para reflejar que era un programa de Python. –

+0

@Mr. Shickadance migró, tendrás que volver a escribir el título si lo crees necesario. – xenoterracide

Respuesta

31

Suponga que su toma se denomina s ... es necesario establecer socket.SO_REUSEADDR en el servidor de socket antes de enlazar a una interfaz ... esto le permitirá reiniciar inmediatamente un servidor TCP ...

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
s.bind((ADDR, PORT)) 
+0

Creo que quiere decir ' setsockopt', y lo intenté pero todavía no tuve suerte. Voy a informar de nuevo después de más pruebas. –

+0

@Mr. Shickadance, sí, es 'setsockopt()' ... Me equivoqué –

+0

Estaba equivocado, esto de hecho resolvió el problema ... ¡y es por eso que mencioné más pruebas! No estaba presionando el código nuevo y modificado antes de ejecutar la prueba (no estoy seguro de cómo lo olvidé). ¡Gracias! –

10

Es posible que desee intentar utilizar Twisted para su red. Mike dio la respuesta correcta de bajo nivel, SO_REUSEADDR, pero no mencionó que esta no es una muy buena opción para configurar en Windows. Este es el tipo de cosas que Twisted cuida automáticamente de usted. Hay muchos, muchos otros ejemplos de este tipo de detalles aburridos de bajo nivel a los que tiene que prestar atención cuando usa el módulo de socket directamente, pero que puede olvidar si usa una biblioteca de nivel superior como Twisted.

+2

'esta no es una muy buena opción para configurar en Windows'. Por qué no? – EJP

+5

En Windows, REUSEADDR permite que un proceso se haga cargo de un puerto de escucha de otro ** proceso que se está ejecutando **. –

+1

Bueno, esto se migró de unix.stackexchange.com, por lo que Windows probablemente no es una gran preocupación. Buen punto de todos modos. + 1 –

2

Estás confundiendo tomas de corriente, conexiones y puertos. Los sockets son puntos finales de las conexiones, que a su vez son 5-tuplas {protocolo, local-ip, local-port, remote-ip, remote-port}. El SO ha cerrado el zócalo del programa destruido y lo mismo ocurre con la conexión. La única reliquia de la conexión es el zócalo del par y el puerto correspondiente en el host par. Entonces, lo que realmente debería preguntar es cómo reutilizar el puerto local . A la que la respuesta es SO_REUSEADDR según las otras respuestas.

Cuestiones relacionadas