PDA

Visualizza la versione completa : [PYTHON] Multiprocessing e socket


leonix
11-07-2012, 14:52
Sono novizio con Python, sto cercando di costruire un piccolo demone che gestisca 5 socket contemporaneamente, e nel caso in cui tutti e cinque siano collegati, effettui un ping su ognuno di essi ogni trenta secondi, per liberarne uno appena possibile.

Codice server:


import threading, socket, time, sys
from multiprocessing import Process
local_address="localhost"

class daemon(threading.Thread):

socket_server = None
socket_list = [[None, None], [None, None], [None, None], [None, None], [None, None]]
socket_timeout = 30
pinged_socket = [False, False, False, False, False]
pinger_process = [None, None, None, None, None]
__local_port=None

def __init__(self, local_port=24585, thread_id=1):
threading.Thread.__init__(self)
#self.daemon=True
self.id=thread_id
self.__local_port=local_port

def run(self):
try: # tentativo di inizializzazione del socket server che gestisce le connessioni
self.socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket_server.bind((local_address, self.__local_port))
self.socket_server.listen(5)
except socket.error as e:
print("daemon couldn't open a socket server: "+str(e))
sys.exit(1)
error_counter=0
count=0;
try: # gestione delle connessioni: 1) accettazione; o se gia presente 2) ping
while True:
if self.socket_list[count] == [None, None]:
self.socket_list[count][0], self.socket_list[count][1] = self.socket_server.accept() # 1) accettazione
else:
if not self.pinged_socket[count]:
self.pinged_socket[count]=True
print("set pinged_socket[",count,"] to ",self.pinged_socket[count])
self.pinger_process[count]=Process(target=self.PingSock, args=(count,)) # 2) ping ed eventuale chiusura
self.pinger_process[count].start()
if count==4:
count=0
else:
count+=1
except KeyboardInterrupt: # gestione dell'interruzione forzata da parte dell'utente del programma: chiusura sockets
for i in range(len(self.socket_list)):
if self.socket_list[i] != [None, None]:
error_counter+=self.ShutdownAndCloseSock(i)
sys.exit(error_counter)

def ShutdownAndCloseSock(self, sock_num): # chiude un socket dell'oggetto daemon e ne azzera il wrapper (daemon.socket_list[])
return_value=0
try:
self.socket_list[sock_num][0].shutdown(socket.SHUT_RDWR)
except socket.error as e:
print("daemon couldn't shut down socket n.%(sock_num)s: %(error_msg)s" %{"sock_num":sock_num, "error_msg":str(e)})
return_value+=1
finally:
try:
self.socket_list[sock_num][0].close()
except socket.error as e:
print("daemon couldn't close socket n.%(sock_num)s: %(error_msg)s" %{"sock_num":sock_num, "error_msg":str(e)})
return_value+=1
self.socket_list[sock_num] = [None, None]
return return_value

def KillDaemon(self): # chiude tutti gli eventuali socket aperti dal daemon e forza l'uscita
errors=0
for i in range(len(self.socket_list)):
if self.socket_list[i] != [None, None]:
errors+=self.ShutdownAndCloseSock(i)
exit(errors)

def PingSock(self, socket_number): # processo adibito al ping di un socket di un oggetto daemon ed eventuale chiusura dello stesso
closed_socket=0
self.socket_list[socket_number][0].settimeout(self.socket_timeout)
try:
self.socket_list[socket_number][0].send(b'ping')
resp = self.socket_list[socket_number][0].recv(256)
if resp!= b'pong' or resp==None:
closed_socket+=self.ShutdownAndCloseSock(socket_nu mber)
print("closed sock ",socket_number," because not ponging: ",resp)
else:
self.socket_list[socket_number][0].settimeout(None)
except socket.timeout:
closed_socket+=self.ShutdownAndCloseSock(socket_nu mber)
print("closed sock ",socket_number," for timeout")
self.pinged_socket[socket_number]=False
print("set pinged_socket[",socket_number,"] to",self.pinged_socket[socket_number])
return closed_socket



d=daemon()
d.start()


normalmente avvio questo daemon (dmn.py) import dmn
e poi avvio il seguente client di prova che connette subito tutti e cinque i socket disponibili, poi perņ lascia che uno di essi decada per timeout non rispondendo "pong".

Codice client:


import socket, time

sock=[None, None, None, None, None]
data=[None, None, None, None, None]

for i in range(5):
sock[i]=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock[i].connect(("localhost",24585))

time.sleep(5)

#def read(i):
while True:
for i in range(4):
time.sleep(1)
data[3-i]=sock[3-i].recv(1024)
print(data[3-i])
if data[3-i]==b'ping':
sock[3-i].send(b'pong')
print("---------------")


def KillAll():
for i in range(5):
try:
sock[i].shutdown(socket.SHUT_RDWR)
sock[i].close()
except socket.error:
print("socket already closed: "+str(i))
exit(0)




Nella shell del server sembra funzionare tutto perfettamente, ma se dopo aver:
1) avviato il daemon
2) avviato il client
3) atteso la disconnessione del socket inattivo

cerco di leggere il valore di dmn.d.socket_list oppure di dmn.d.pinged_socket, ottengo valori totalmente inaspettati:

Output del demone


>>> import dmn
>>> set pinged_socket[ 0 ] to True
set pinged_socket[ 1 ] to True
set pinged_socket[ 2 ] to True
set pinged_socket[ 3 ] to True
set pinged_socket[ 4 ] to True
set pinged_socket[ 3 ] to False
set pinged_socket[ 2 ] to False
set pinged_socket[ 1 ] to False
set pinged_socket[ 0 ] to False
closed sock 4 for timeout
set pinged_socket[ 4 ] to False

>>> dmn.d.pinged_socket
[True, True, True, True, True] <------------------ ??????????
>>> dmn.d.socket_list
[[<socket.socket object, fd=3, family=2, type=1, proto=0>, ('127.0.0.1', 58151)], [<socket.socket object, fd=5, family=2, type=1, proto=0>, ('127.0.0.1', 58152)], [<socket.socket object, fd=6, family=2, type=1, proto=0>, ('127.0.0.1', 58153)], [<socket.socket object, fd=7, family=2, type=1, proto=0>, ('127.0.0.1', 58154)], [<socket.socket object, fd=8, family=2, type=1, proto=0>, ('127.0.0.1', 58155)]]
>>> dmn.d.socket_list[4][0].send(b'hi')
Traceback (most recent call ast):
File "<stdin>", line 1, in <module>
socket.error: [Errno 32] Broken pipe


il socket risulta a tutti gli effetti chiuso, ma le funzioni della mia classe daemon non aggiornano le variabili pinged_socket e socket_list

cosa posso fare? darmi all'ippica?

Loading