Il modulo microsock
Quando viene creato un socket usando il wrapper ntk.wrap.sock.Sock, viene registrato nella mappa di asyncore e viene avviato un microthread nel modulo microsock.
La mappa di asyncore associa il fd (file descriptor, un numero intero) all'oggetto (che può essere un file, o un socket, ...).
Il microthread avviato esegue la funzione ManageSockets. Questa richiama asyncore.poll(0.05) ciclicamente (intervallando con micro_block per passare lo scheduler agli altri) fin quando esiste un socket (nel caso di netsukuku per sempre) nella mappa di asyncore.
Nota: asyncore.poll usa time.sleep per attendere il timeout specificato anche quando non ci sono oggetti su cui ascoltare. Questo sleep non è un busy wait per il sistema operativo. Però non passa lo scheduler agli altri microthread. Per questo dobbiamo richiamarlo con piccoli timeout intervallando con chiamate a micro_block. Vedi il modulo xtime.
Il metodo asyncore.poll, tramite il metodo select.select, scopre quali dei socket registrati nella sua mappa ha dei dati da inviare o da ricevere.
Vediamo quali passi segue la creazione e connessione di un socket, prima di analizzare quello che avviene quando si trasmette o riceve qualcosa.
Quando si crea un socket all'interno del programma (con socket.socket(...)) viene effettivamente creato un vero socket (con stdsocket.socket(...)) e anche un microsock.stacklesssocket, che è l'oggetto restituito. Questo memorizza il vero socket e una istanza dell'oggetto microsock.dispatcher, anch'esso a conoscenza del vero socket.
In seguito tutte le chiamate __getattr__ al finto socket (cioè all'oggetto stacklesssocket ritornato) vengono inoltrate al dispatcher (esempi di queste chiamate sono s.listen, s.bind, ...) mentre le chiamate __setattr__ vengono memorizzate localmente. ???
Nel frattempo, avendo istanziato un dispatcher, che è una derivata di asyncore.dispatcher, abbiamo anche fatto altro:
- la classe ha i membri connectChannel, acceptChannel e recvChannel.
- istanziato per recvChannel un Channel con micro_send = True.
- preparato una stringa buffer e una lista per i send (sendBuffer e sendToBuffers)
- preparato una stringa buffer e una lista per i recv (readBufferString e readBufferList)
- preparato una costante maxreceivebuf = 65536
memorizzato il vero socket nella mappa di asyncore (questo lo fa asyncore.__init__ => asyncore.set_socket => asyncore.add_channel)
la sua rimozione dalla mappa avviene con stacklesssocket.__del__ => asyncore.close => asyncore.del_channel
Prima che un socket abbia qualcosa da inviare o ricevere, di norma viene connesso richiamando in esso il metodo connect o listen e poi accept.
