[Python-es] problema con hilos

jose villalba cortazzo josemariavillalbacortazzo en hotmail.com
Lun Jul 2 04:05:31 CEST 2012


Gente como puedo hacer para matar a los hilos socketudp y socketcp para que el programa se cierre solo y libere los recursos que esta utilizando.
El programa es un cliente p2p que envía mensajes y transfiere archivos a otros clientes.
Al arrancar el sistema hay que especificar el puerto por donde va a escuchar conexiones TCP y modificar la dirección de broadcast por la de su red para probarlo.
Estoy estudiando socket.  
Saludos.
José
Codigo:
import socket
import threading
import re
import time
import string
import os
from Queue import Queue

tamaniomensaje = 255
tamanioarchivo = 65535 
 
class TCPSOCKET(threading.Thread):
    def __init__(self, puerto, cola):
        threading.Thread.__init__(self)
        self.puerto = puerto
        self.cola = cola
    
    def run(self):
        s = socket.socket()
        s.bind(("",self.puerto))
        s.listen(5)  #escuchamos solo a uno por vez
        archivo = False
        
        while True:
            salir = cola.get()
            if salir == True:
                s.close()
                print 'Fin de la historia TCP'
                break
 
            sc, direccion = s.accept()
            if archivo == False:
                #Fecha y hora actual
                hoy = "[%4d.%2.2d.%2.2d %2.2d:%2.2d] " %time.localtime()[:5]
                #  se crea ulana conexion nueva por cada mensaje (para evitar problemas en esperas largas)
                try:
                    mensaje = sc.recv(tamaniomensaje)
                except socket.timeout:
                    print "Cerrado por inactividad"
                    sys.exit()
                    break
                    
                mensajelista = mensaje.split(' ')
                mensaje = str(hoy + direccion[0]) + ' '+mensaje
                print mensaje
            
                #pasa el mensaje a una lista para poder analizarlo.
                if mensajelista[0] == '&file':
                    archivo = True
                    #ruta donde se va almacenar el archivo que va recibir(
                    ruta = os.getcwd()+'/'+mensajelista[1]
                
            elif archivo == True:
                #Crea un archivo vacio para poder almacenar el contenido del archivo que va recivir.
                vacio = open(ruta, 'wb')
                #recibe el contenido.
                contenido = sc.recv(tamanioarchivo)
                #Escribe el contenido en el archivo vacio.
                vacio.write(contenido) 
                #Cierra el archivo.
                vacio.close()
                #Establecemos la variale archivo a false.
                archivo = False 
            sc.close()  #se cierra la conexion

class UDPSOCKET(threading.Thread):    
    def __init__(self, puerto, cerrar):
        threading.Thread.__init__(self)
        self.socketdatagrama = ''
        self.puerto = puerto
        self.f = False
        self.ruta =''
        self.cerrar = cerrar
    
    def run(self):
        espacio = ' '
        msg = 'ON'
        while msg != 'OK':
            msg =self.cerrar.get()
            if msg == 'OK':
                print msg
                break
            else:
                hoy = "[%4d.%2.2d.%2.2d %2.2d:%2.2d] " %time.localtime()[:5]
                self.socketdatagrama = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                self.socketdatagrama.bind(('',self.puerto))
                mensaje, cliente = self.socketdatagrama.recvfrom(1024)
                #pasamos el mensaje a una lista para poder analizarlo
                informacion = mensaje.split(espacio)
                
                #Analiza si se va recibir un archivo o un mensaje siplemente
                if informacion[0] == '&file' and len(informacion)>1:
                    #Se utiliza para poder saber si se esta esperando un archivo.
                    self.f = True
                    #mostramos el mensaje
                    mensaje = str(hoy + cliente[0]) + ' '+mensaje
                    print mensaje
                    
                    #ruta donde se va almacenar el archivo que va recibir
                    self.ruta = os.getcwd()+'/'+informacion[1]
                
                elif self.f == False:
                    mensaje = str(hoy + cliente[0]) + ' '+mensaje
                    print mensaje
                
                elif self.f == True:
                    #creamos un archivo para poder almacenar el contenido que vamos a recibir.
                    archivo = open(self.ruta, 'wb')
                    archivo.write(mensaje)
                    archivo.close()
                    self.f = False
                self.socketdatagrama.close()
#Funcion para enviar mensajes a un x destinatario, se crea un socket para poder enviar
#enviar el mensaje y se cieera. 
def enviar_texto(ip,puerto,texto):
    try:
        s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
        s.connect((ip, puerto))
        s.send(texto)
        s.close()
        return True
    except socket.error:
        return False
        
#Funcion para enviar archivo a un x destinatario.
#Se crea un socket, se envia el archivo y se cierra.
def enviar_archivo(ip, puerto, ruta):
    #Abre el arachivo y lo almacena en un buffer para poder enviarcelo al destinatario.
    try:
        archivo = open(ruta, 'rb')
        paquete = archivo.read()
        archivo.close()
        
        #crea el socket para poder enviar el archivo.
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #se conecta al receptor.
        s.connect((ip, puerto))
        #Envia el archivo
        s.send(paquete)
        #Cierra el socket
        s.close
    except IOError:
        print 'Ruta incorrecta'

#Valida la IP a la cual se desea enviar un mensaje,
def ValidarIP(ip):
    pattern = r"\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
    if re.match(pattern, ip):
        return True
    else:
        return False

#Funcion para realizar broadcast.
#Se utiliza para poder enviar un mismo mensaje a todos los clientes.
#Utilizamos un socket UDP
def broadcast(puertoudp, mensaje):
    #Creamos el socket
    miSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    miSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    
    espacio = ' '
    #pasa el mensaje a una lista para analizarlo.
    mensaje = mensaje.split(espacio)
    
    #Si el mensaje no contiene un archivo.
    if mensaje[0]!= '&file':
        #Transforma el mensaje a una cadena ya que esta en una lista.
        mensaje = espacio.join(mensaje)
        #Envia el mensaje a toda la red.
        miSocket.sendto(mensaje, ('10.168.1.255', puertoudp))
        
    elif mensaje[0] == '&file' and len(mensaje)>1:
        #Al receptor solo le envia el nombre del archivo.
        ruta = mensaje[1]
        mensaje[1] = os.path.basename(ruta)
        
        #Pasa el mensaje a una cadena para poder enviarlo, el mensaje estaba contenido en una lista.
        mensaje = espacio.join(mensaje)
        
        try:
            #proceso para enviar el archivo.
            #abre ele archivo en modo lectura binaria
            archivo = open(ruta,'rb')
            
            #Alamcena el contenido del archivo mientra se lee en una variable para poder enviarlo.
            f = archivo.read()
            
            #Cierra el archivo.
            archivo.close()
            
            #Comunica a los receptores que va un archivo.
            miSocket.sendto(mensaje, ('10.168.1.255', puertoudp))
            
            #Espera dos segundo para poder enviar el archivo, asi el receptor prepara todo para recibirlo.
            time.sleep(2)
            #Se envia el archivo.
            miSocket.sendto(f, ('10.168.1.255', puertoudp))
        except IOError:
            print 'Ruta incorreta.'
            miSocket.close()
    miSocket.close()


########################################################################
puerto = int(raw_input(''))

while puerto == 9999:
    print 'El puerto no puede ser 9999 ya que es el puerto de broadcast.'
    puerto = int(raw_input(''))

salir = False

cola = Queue()
cerrar = Queue()

cola.put(salir)
cerrar.put('ON')

socketcp = TCPSOCKET(puerto,cola);
socketcp.start()

socketudp = UDPSOCKET(9999,cerrar)
socketudp.start()

espacio = ' '

#Bucle que que recive los mensajes del operador.
while True:
#Pide al operador el mensaje.
    try:
        mensaje = raw_input('')
    except KeyboardInterrupt:
        salir = True
        fin  = True
        cola.put(salir)
        #Mata el hilo socketudp
        cerrar.put('OK')
        break
        
    #Pasa el mensaje a lista para poder analizarlo.
    mensajelista = mensaje.split(espacio)
    #Optiene el primer elemento mensaje para averiguar si el mensaje esta destinado a un
    #unico receptor o a todos.
    IP =  mensajelista[0]   
    
    #Valida la IP
    if ValidarIP(IP):
        #Si el mensaje contiene un archivo
        if len(mensajelista) > 2 and mensajelista[1] == '&file':
            #Extrae la ruta de donde se encuentra ubicado el archivo.
            ruta = mensajelista[2]
            #De la ruta del archivo extrae el nombre del archivo, ya que es lo unico que le va enviar
            #al receptor para que no sepa en que directorio donde esta ubicado el archivo en la PC del emisor.
            mensajelista[2] = os.path.basename(mensajelista[2])
            
            #Pasa mensaje de lista a cadena.
            smsenviar = espacio.join(mensajelista[1:])
            
            #Envia el mensaje al destinatario
            if enviar_texto(IP,puerto,smsenviar):
                #Envia el archivo al destinatario.
                enviar_archivo(IP, puerto,ruta)
            else:
                print 'Error al conectarse al destinatario.'
        #Envia un mensaje en formato texto.
        else:
            smsenviar = espacio.join(mensajelista[1:])
            if enviar_texto(IP, puerto,smsenviar ) == False:
                print 'Destinatario no conectado.'

    #si el mensaje tiene como destino a todos los clientes de la red del usuario.
    elif IP == '*':
        #Al mensaje le elimin el * y se lo pasa a la funcion broadcast para que se lo envie a toda la red.
        smsenviar = espacio.join(mensajelista[1:])
        broadcast(9999, smsenviar)
    else:
        print 'Error al enviar el mensaje.'


 		 	   		  
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://mail.python.org/pipermail/python-es/attachments/20120702/0a041f19/attachment.html>
------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: p2p.py
Type: text/x-python
Size: 8202 bytes
Desc: no disponible
URL: <http://mail.python.org/pipermail/python-es/attachments/20120702/0a041f19/attachment.py>


Más información sobre la lista de distribución Python-es