[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