2012-05-28 11 views
6

Sto imparando a utilizzare HTML5 WebSockets e come parte di ciò sto scrivendo un server in Python in modo da poter conoscere il nocciolo duro di come funzionano. Ne ho creato uno l'altro giorno che funzionava abbastanza bene, ma volevo espanderlo in modo tale che potesse supportare più endpoint con ogni endpoint che fosse un "servizio" diverso in grado di gestire i client websocket.Invia oggetto socket a processo in esecuzione biforcuta (multiprocessing.Queue)

Al momento, la mia implementazione funziona con processi di spawning e così via (sto usando multiprocessing anziché threading da quando ho letto che il threading non è realmente multithreading in CPython e questo è quello che penso sto usando (installazione predefinita su Ubuntu 12.04)), ma sto riscontrando problemi nell'invio dei socket client ricevuti ai processi di servizio.

Ecco come li rimando (questo viene eseguito in un ciclo):

try: 
    #get a new client 
    conn, addr = server.accept() 
    print "Client connected from", addr 
    request = conn.recv(4096) 
    response, close, service = self.handshake(request) 
    conn.send(response) 
    if close: 
     print "Invalid request from", addr 
     conn.close() 
     continue 
    client = WebSockets.WebSocketClient(conn, addr) 
    service.clientConnQueue.put(client) 

'server' è una presa in ascolto per le connessioni in entrata. Il metodo di handshake si occupa di convalidare la loro richiesta e determinare quale processo di servizio inserire il cliente. 'response' è la risposta http da inviare, 'close' è True se c'è stato un errore, e 'service' è una classe che eredita da multiprocessing.Queue. WebSocktes.WebSocketClient è dove la mia invio e la ricezione di attuazione viene memorizzato e fondamentalmente funziona come un wrapper per una presa di corrente.

'clientConnQueue' si crea in questo modo:

class Service(multiprocessing.Process): 
    """Base class for all services.""" 
    def __init__(self, manager): 
     multiprocessing.Process.__init__(self) 
     self.manager = manager 
     self.clientConnQueue = self.manager.Queue() 
     self.shutdownFlag = multiprocessing.Event() 

manager è un multiprocessing.Manager()

L'errore che ottengo quando provo a mettere un cliente nel clientConnQueue è la seguente:

File "./WebSocketServer.py", line 183, in <module> 
main() 
File "./WebSocketServer.py", line 180, in main 
server.runServer() 
File "./WebSocketServer.py", line 67, in runServer 
service.clientConnQueue.put(client) 
File "<string>", line 2, in put 
File "/usr/lib/python2.7/multiprocessing/managers.py", line 758, in _callmethod 
conn.send((self._id, methodname, args, kwds)) 
TypeError: expected string or Unicode object, NoneType found 

Ho quindi un errore di tubo rotto sul lato di ricezione.

Ho ricevuto lo stesso errore quando stavo usando un multiprocessing.Queue per inviare la connessione e ho pensato che modificarlo in una coda creata da un gestore avrebbe risolto il problema. Tuttavia, sembra fare esattamente la stessa implementazione.

Chiaramente questo non è il modo in cui si suppone di inviare qualcosa di simile a un processo in esecuzione, quindi qual è il modo corretto per inviare oggetti non serializzabili a un processo?

risposta

1

Passare il socket a un altro processo non è cosa da poco. Guarda, ad esempio, questa domanda: Can I open a socket and pass it to another process in Linux

In ogni caso, i processi o i thread del sistema operativo non sono ciò che si desidera realmente per l'implementazione del server Websocket, a causa dell'ampio overhead di memoria. Guarda smth con prese non bloccanti ...ad es., Tornado http://www.tornadoweb.org/documentation/websocket.html

+1

Ogni socket client non avrà necessariamente il proprio thread, ma ogni servizio ottiene il proprio processo/thread e viene lasciato al servizio esattamente cosa fare con il socket. Questo è un buon punto anche se ... i server http non hanno a che fare con la possibilità di 1000 connessioni simultanee di lunga durata e questo è un sovraccarico di memoria se ogni connessione ha il suo thread. –

0

Non è possibile inviare socket ai processi biforcati senza utilizzare deep unix magic. Puoi leggere il libro Programmazione avanzata nell'ambiente Unix se vuoi veramente vedere come è fatto in C.

Per una soluzione semplice, cambia l'uso della filettatura e il tuo codice probabilmente funzionerà. Mentre il threading non è perfetto in Python, è abbastanza buono per fare roba intensa per IO.

In alternativa, creare la presa di ascolto prima di eseguire la foratura e ottenere tutti i sottoprocessi da ascoltare (chiamare accept). Il sistema operativo assicurerà che solo uno di loro ottenga la connessione. In questo modo vengono solitamente scritti i server di preforking.

1

È in circolazione da 4+ anni, anche se richiede un po 'di lavoro.

L'intestino è sospeso in multiprocessing.reduction e i dettagli di un esempio possono essere visualizzati in this github gist.

0

Se si crea un socket prima del processo di forking, il relativo descrittore di file verrà ereditato dai bambini.

Problemi correlati