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: [email protected]
To: [email protected]; [email protected]
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: [email protected]
> To: [email protected]
> Subject: Re: [Python-es] problema con hilos
>
> El día 2 de julio de 2012 04:05, jose villalba cortazzo
> <[email protected]> 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
> [email protected]
> http://mail.python.org/mailman/listinfo/python-es
> FAQ: http://python-es-faq.wikidot.com/
_______________________________________________
Python-es mailing list
[email protected]
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
[email protected]
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/