[Python-es] ¿Como cierro correctamente un hilo-servidor de sockets?
gerardo Juarez
gerardojuarez en buyteknet.info
Vie Ago 26 21:53:06 CEST 2011
Efectivamente Sergio, es el mismo comportamiento que yo he observado: la
aplicación cierra el socket, termina y aún así, pasan algunos segundos
para que el puerto quede disponible nuevamente. No me parece que sea un
problema directamente atribuible a tu aplicación, sino más bien a la
forma en que el sistema libera -o registra- que los puertos han sido
liberados. Habría que informarse cómo está implementada la función
'restart' de los servicios de Linux, por ejemplo, porque allí terminan
un servicio y lo reinician tan pronto como es posible. De qué modo
averiguan que ya está disponible el puerto?
Sergio Martín wrote:
> Pero al cerrar el socket del servidor (como comento en mi segundo
> mensaje) ¿no debería liberarse el puerto?
> Por otro lado ¿como puedo cerrar el hilo si lo tengo en espera de un
> cliente? ¿Hay alguna otra forma aparte de salir del bucle infinito que
> tengo?
>
> El 26 de agosto de 2011 15:10, chakalinux <chakalinux en gmail.com
> <mailto:chakalinux en gmail.com>> escribió:
>
> En la interrupcion KeyboardInterrupt tienes que cerrar los hilos
> para que no se te quede el mismo en CLOSE_WAIT que en ciertos
> casos puede durar bastante en liberarse.
>
> De todas maneras yo te recomiendo que uses la librería select o
> asyncore para manejar socket's, intenta evitar cuando puedas
> sockets y threading
>
> El 26 de agosto de 2011 02:21, Sergio Martín
> <sergiomartinj en gmail.com <mailto:sergiomartinj en gmail.com>> escribió:
>
> Comentar que aunque añada la línea:
> self.socketserver.close()
> en el método close() de la clase TelnetServer el resultado es
> el mismo.
>
> El día 26 de agosto de 2011 02:17, Sergio Martín
> <sergiomartinj en gmail.com <mailto:sergiomartinj en gmail.com>>
> escribió:
> > Tengo un script en el que, primero, ejecuto un servidor de
> sockets en
> > un hilo, y cada conexión que reciba, genera su propio hilo.
> > El problema viene cuando intento salirme del programa
> mediante una
> > excepción KeyboardInterrupt controlada, funciona bien si no
> ha habido
> > ninguna conexión al socket-servidor, pero si me salgo del
> programa una
> > vez que he recibido alguna conexión, y, a continuación
> ejecuto el
> > programa de nuevo, me sale un "socket.error: [Errno 48] Address
> > already in use", como si no hubiese cerrado el socket del
> servidor
> > correctamente, teniéndome que esperar un rato hasta que se
> libere el
> > puerto.
> > Tengo controladas dos situaciones una que desde el cliente
> telnet se
> > pase el comando "quit", con lo que cierro el socket del
> cliente, y
> > otra cuando se pierde la conexión con el cliente sin
> introducir el
> > comando "quit"
> > El error solo me lo lanza cuando he salido por medio del "quit".
> >
> > Aviso que está escrito en python3, y se que hay mejores
> formas de
> > hacer esto en vez de usar hilos, como el módulo twisted (sin
> > compatibilidad python3) o el asyncore, pero solo tengo planeado
> > recibir un par de conexiones simultáneas por lo que no se
> generarán
> > muchos hilos.
> >
> > Pongo una versión simplificada del programa, con solo lo
> básico para
> > ilustrar el problema:
> >
> > #! /usr/bin/env python3
> >
> > import threading
> > import socket
> > import sys
> > import time
> >
> > class TelnetServer(threading.Thread):
> >
> > def __init__(self):
> > threading.Thread.__init__(self)
> > self.socketserver = socket.socket()
> > self.socketserver.bind(('', 9999))
> > self.socketserver.listen(5)
> >
> > def run(self):
> > print('Servidor en marcha')
> > while True:
> > socketclient, addr = self.socketserver.accept()
> > client = TelnetClient(socketclient, addr)
> > client.start()
> >
> > def close(self):
> > print('Servidor detenido')
> >
> > class TelnetClient(threading.Thread):
> >
> > def __init__(self, socketclient, addr):
> > threading.Thread.__init__(self)
> > self.socketclient = socketclient
> > self.addr = addr
> >
> > def run(self):
> > print('Conexión: %s:%s' % (self.addr[0], self.addr[1]))
> > while True:
> > try:
> > command, args = self.prompt()
> > except socket.error:
> > self.close()
> > break
> >
> > if command == None:
> > pass
> > elif command == 'quit':
> > self.close()
> > break
> > else:
> > self.send('Comando desconocido\n')
> >
> > def send(self, msg):
> > self.socketclient.send(msg.encode('utf8'))
> >
> > def recv(self):
> > return self.socketclient.recv(1024).decode('utf8')[:-2]
> >
> > def prompt(self):
> > try:
> > self.send('prompt> ')
> > recv_list = self.recv().split()
> > return recv_list[0].lower(), recv_list[1:]
> > except IndexError:
> > return None, []
> >
> > def close(self):
> > self.socketclient.close()
> > print('Desconexión: %s:%s' % (self.addr[0],
> self.addr[1]))
> >
> > if __name__ == '__main__':
> > try:
> > telnetserver = TelnetServer()
> > telnetserver.daemon = True
> > telnetserver.start()
> >
> > while True:
> > time.sleep(100)
> >
> > except KeyboardInterrupt:
> > telnetserver.close()
> > sys.exit()
> >
> _______________________________________________
> Python-es mailing list
> Python-es en python.org <mailto:Python-es en python.org>
> http://mail.python.org/mailman/listinfo/python-es
> FAQ: http://python-es-faq.wikidot.com/
>
>
>
> _______________________________________________
> Python-es mailing list
> Python-es en python.org <mailto:Python-es en python.org>
> http://mail.python.org/mailman/listinfo/python-es
> FAQ: http://python-es-faq.wikidot.com/
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Python-es mailing list
> Python-es en python.org
> http://mail.python.org/mailman/listinfo/python-es
> FAQ: http://python-es-faq.wikidot.com/
>
Más información sobre la lista de distribución Python-es