2011-02-18 21 views
7

Soy nuevo en la programación de sockets y me encontré con un problema desconcertante:toma Python hace conexión no se cierre correctamente

que tienen un programa de Windows que no puedo alterar (software propietario), pero que intenta conectarse a una dirección IP específica y puerto con un zócalo de tcp.

En mi linux box escribí un pequeño script de python para servir el socket al win prog. Esto funciona bien hasta que mate mi programa en Linux. El socket del servidor inicial no se cierra como se especificó y no puedo reiniciar mi programa hasta que el socket sea basura.

Si intento lo mismo con un socket de Linux (en un script de python separado) no tengo problemas.

Aquí es un ejemplo de código mínima:

import socket 

server = socket.socket() 
server.bind(('192.168.0.111', 50001)) 
server.listen(1) 
conn, addr = server.accept() 
print 'Connection established' 

running = True 
while running: 
    try: 
     data = conn.recv(4096) 
    except KeyboardInterrupt: 
     conn.close() 
     running = False 
    else: 
     if data: 
      print data 
     else: 
      conn.close() 
      running = False 
server.close() 

Si mato esto con Ctrl-C que sale normalmente. Pero al reiniciar el script me sale un socket.error que indica que la dirección ya está en uso. Después de un minuto o así el programa funciona nuevamente.

También probé un apagado antes del cierre (también conocido como conn.shutdown (2) y server.shutdown ...) pero eso no tiene ningún efecto.

¿Hay una mejor manera "correcta" de cerrar un socket de Windows? ¿Extraño algo fundamental sobre los enchufes en general?

Gracias!

edición: Creo que acabo de ver la respuesta aquí: what is the correct way to close a socket in python 2.6?

Aunque estoy usando Python 2.5 todavía podría funcionar.

+0

'echo "desconexión" | nc 192.168.1.12 58888 -w 1' - del lado del cliente puede hacer un tiempo de espera de 1 segundo y dejar que el servidor tenga su propio time_out – YumYumYum

Respuesta

24

Usted está experimentando el estado de TIME_WAIT enchufes conectados. Aunque hayas cerrado tu socket, todavía tiene consecuencias persistentes durante un par de minutos. Las razones para esto, así como un indicador de socket que puede configurar para deshabilitar el comportamiento (SO_REUSEADDR), se explican en el UNIX guide socket FAQ.

En resumen,

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
+0

El estado TIME_WAIT de los sockets * connected *. – EJP

+0

¡De hecho! Gracias. –

2

Intente agregar import sys y finalizar su aplicación con sys.exit(). El socket permanece reservado hasta que el sistema esté satisfecho de que la aplicación está cerrada. Puede ser explícito al respecto con sys.exit()

[edit] Oh, ok. Soy bastante nuevo para enchufes yo mismo. Entonces, ¿estás diciendo que esta secuencia no es segura? No puedo imaginar otra forma de hacerlo. Tienes que cerrar tu aplicación en algún momento, con alguna técnica, ¿verdad? ¿Cómo se hace correctamente entonces?

server.shutdown(socket.SHUT_RDWR) 
server.close() 
sys.exit() 
+0

De hecho, también pensé en eso y lo tuve en mi script. Si esto tuvo un efecto en la demora hasta que se cerró el socket, fue insignificante. – BandGap

+0

No recomendaría usar sys.exit(). Podría terminar con un socket colgado, muy raro en Unix, que no es raro en Windows. Si cuelga un socket en Windows, deberá reiniciar para repararlo. – KaizenSoze

+0

sys.exit() no es realmente diferente de cualquier otra forma de salir de un proceso de Python. Entonces, tu consejo es "no salir si creaste un zócalo", lo cual es un poco impráctico. Si tus programas nunca salen, probablemente tendrás que reiniciar también.;) En general, Windows es bastante simple, y cosas como firewalls y software antivirus pueden hacer que * aún más * flakey. Sin embargo, salir de un proceso que tenía tomas abiertas probablemente sea básicamente seguro todo el tiempo, y si no lo es, su sistema tendrá tantos problemas que no notará un programa problemático de Python. –

Cuestiones relacionadas