Ejemplo de ejecución: ********************************************************************************* jose@pepe:/media/DATOS/usuario/Mis Documentos Usuario/p2p$ python p2p.py 9000 10.168.1.110 &file /home/jose/prueba.txt [2012.07.02 18:10] 10.168.1.110 &file prueba.txt * hola [2012.07.02 18:10] 10.168.1.110 hola * &file /home/jose/prueba.txt [2012.07.02 18:10] 10.168.1.110 &file prueba.txt 10.168.1.110 quien sos? [2012.07.02 18:11] 10.168.1.110 quien sos? python Error al enviar el mensaje. 10.168.1.113 estas? Destinatario no conectado 10.1.134.5 prueba #se cuelga y reacciona al rato. Destinatario no conectado ********************************************************************** Tengo un solo erro pero funciona bien, el erro es que cuando intento conectarme a un cliente que no pertenece a mi subred el sistema queda colgado por un tiempo importante hasta que reacciona indicándome que el receptor no existe. Adjunto el código. Saludos. From: josemariavillalbacorta...@hotmail.com To: p...@ch3m4.org; python-es@python.org Date: Mon, 2 Jul 2012 20:07:38 +0000 Subject: Re: [Python-es] problema con hilos
Tus consejos me han servido. Lo que estoy programando en un cliente p2p y estaba teniendo problema para cerrar totalmente el programa al ingresar Ctrl + C. El funcionamiento es el siguiente: Al ingresar el operador tiene que ingresar el puerto por donde va escuchar al resto de los clientes. Para mandar un mensaje a un x cliente tiene que ingresar la IP del destinatario + espacio+ mensaje Para mandar un mensajes a todos los clientes p2p de la red tiene que ingresar * + espacio+ mensaje. Para mandar un archivo a un x cliente IP del destinatario+espacio+ &file+ruta donde se encuentra el archivo, el receptor almacena el archivo en su directorio de trabajo actual. Para mandar un archivo a todos los clientes de la red *+espacio+&file+ruta donde se encuentra el archivo. Adjunto el trabajo final para ver si alguien le puede realizar alguna mejora, una de las mejoras que le tengo que realizar es que al arrancar el programa tome automáticamente la dirección de broadcast de la red donde se esta ejecutando. Saludos, José. > Date: Mon, 2 Jul 2012 13:50:35 +0200 > Froim: pych...@gmail.com > To: python-es@python.org > Subject: Re: [Python-es] problema con hilos > > El día 2 de julio de 2012 04:05, jose villalba cortazzo > <josemariavillalbacorta...@hotmail.com> escribió: > > 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. > > Podías explicar un poco qué es lo que te pasa. > > Por experiencia, supongo que los sockets no muestran los mensajes de > cierre y se te queda todo colgado. El hilo principal no puede terminar > porqué todavía tiene hijos en activo, y los hijos están bloqueados > porque el padre no suelta el control. > > Soluciones: > > 1) haz que los hijos sean "daemons". De este modo, cuando el padre > termina, los hijos se interrumpen. El incoveniente es que los hijos no > acaban bien. > > def __init__(self, puerto, cerrar): > threading.Thread.__init__(self) > self.daemon=True > > 2) Haz que el padre espere a que terminen los hijos. > > except KeyboardInterrupt: > cola.put(salir) > cerrar.put('OK') > > socketcp.join() > socketudp.join() > > break > > 3) Cuando hay muchos hijos, resulta más práctico esperar a que los > queues se haya vaciado: > > except KeyboardInterrupt: > cola.put(salir) > cerrar.put('OK') > > cola.join() > cerrar.join() > > break > > Pero hace falta que en cada get tenga emparejado un task_done para > indicar que ha terminado el procesado del dato extraído: > > while True: > salir = cola.get() > ... > cola.task_done() > > > Aunque no uses este método, haz siempre el task_done() al finalizar el > procesado. > > > > > -- > Hyperreals *R: http://ch3m4.org/blog > Quarks, bits y otras criaturas infinitesimales > _______________________________________________ > Python-es mailing list > Python-es@python.org > http://mail.python.org/mailman/listinfo/python-es > FAQ: http://python-es-faq.wikidot.com/ _______________________________________________ Python-es mailing list Python-es@python.org http://mail.python.org/mailman/listinfo/python-es FAQ: http://python-es-faq.wikidot.com/
import socket import threading import re import time import string import os import sys tamaniomensaje = 255 tamanioarchivo = 65535 class TCPSOCKET(threading.Thread): def __init__(self, puerto): threading.Thread.__init__(self) self.puerto = puerto self._stop = False self.daemon = True def stop(self): self._stop = True def run(self): s = socket.socket() s.bind(("",self.puerto)) s.listen(5) #escuchamos solo a uno por vez archivo = False while True: #Mata al hilo. if self._stop == True: s.close() 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): threading.Thread.__init__(self) self.socketdatagrama = '' self.puerto = puerto self.f = False self.ruta ='' self._stop = False self.daemon=True def stop(self): self._stop = True def run(self): espacio = ' ' while True: #Mata al hilo. if self._stop == True: break 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 por donde el cliente va escuchar al resto de los clientes de la red. puerto = int(raw_input('')) #Analiza que el puerto tenga que sea detinto de 9999 ya que este puerto esta asociado al boradcast. while puerto == 9999: print 'El puerto no puede ser 9999 ya que es el puerto de broadcast.' puerto = int(raw_input('')) #Inciamos el socket TCP socketcp = TCPSOCKET(puerto); socketcp.start() #Inciamos el socket UDP socketudp = UDPSOCKET(9999) socketudp.start() espacio = ' ' #Bucle que que recive los mensajes del operador. while True: #Pide al operador el mensaje. try: mensaje = raw_input('') #Cerramos el programa. except KeyboardInterrupt: #socketudp.join(0.1) #socketcp.join(0.1) socketcp.stop() socketudp.stop() 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:]) control = enviar_texto(IP, puerto,smsenviar) if control == 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.'
_______________________________________________ Python-es mailing list Python-es@python.org http://mail.python.org/mailman/listinfo/python-es FAQ: http://python-es-faq.wikidot.com/