[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