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:
codice:
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_number)
        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_number)
      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:
codice:
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
codice:
>>> 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?