2012-05-28 11 views
6

Estoy aprendiendo a usar HTML5 WebSockets y como parte de eso estoy escribiendo un servidor en Python para que pueda conocer los detalles de cómo funcionan. Creé uno el otro día que funcionó bastante bien, pero quería expandirlo para que admitiera múltiples puntos finales, con cada punto final como un "servicio" diferente que puede manejar clientes de websocket.Enviar el objeto socket al proceso de ejecución bifurcado (multiprocesamiento.Queue)

Por el momento, mi aplicación trabaja con los procesos de desove y tal (estoy usando multiprocesamiento en lugar de enhebrado desde que leí que la rosca no es realmente multihilo en CPython y eso es lo que pienso que estoy usando (instalación por defecto en Ubuntu 12.04)), pero tengo problemas para enviar los sockets de clientes recibidos a los procesos de servicio.

Así es como los mando (esto se ejecuta en un bucle):

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) 

'servidor' es un socket de escucha para las conexiones entrantes. El método handshake se encarga de validar su solicitud y determinar en qué proceso de servicio colocar al cliente. 'response' es la respuesta http para enviar, 'close' es True si hubo un error, y 'service' es una clase que hereda de multiprocessing.Queue. WebSocktes.WebSocketClient es donde se almacena la implementación de envío y recepción y básicamente funciona como un contenedor para un socket.

'clientConnQueue' se crea de este 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() 

director es un multiprocessing.Manager()

El error que consigo cuando intento de colocar un cliente en el clientConnQueue es el siguiente:

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 

Luego recibo un error de tubería rota en el lado de recepción.

Recibí el mismo error cuando estaba usando un multiprocesamiento.Queue enviar la conexión y pensé que cambiarlo a una cola creada por un administrador solucionaría el problema. Sin embargo, parece hacer la misma implementación exacta.

Claramente esta no es la forma en que se supone que se debe enviar algo como esto a un proceso en ejecución, entonces, ¿cuál es la forma correcta de enviar objetos no serializables a un proceso?

Respuesta

1

Pasar socket a otro proceso no es algo trivial. Mira, por ejemplo, esta pregunta: Can I open a socket and pass it to another process in Linux

De todos modos, los procesos del sistema operativo o los hilos no es lo que realmente quiere para implementar servidor de WebSocket, debido a la gran sobrecarga de memoria. Mira lo mismo con enchufes sin bloqueo ...por ejemplo, Tornado http://www.tornadoweb.org/documentation/websocket.html

+1

Cada socket de cliente no necesariamente obtendrá su propio hilo, pero cada servicio obtiene su propio proceso/hilo y le deja al servicio exactamente qué hacer con el socket. Sin embargo, ese es un buen punto ... los servidores http no tienen que lidiar con la posibilidad de 1000 conexiones simultáneas de larga duración y eso implica una gran cantidad de memoria si cada conexión tiene su propio hilo. –

0

No puede enviar sockets a procesos bifurcados sin utilizar la magia profunda de Unix. Puede leer el libro Programación avanzada en el entorno Unix si realmente desea ver cómo se hace en C.

Para una solución sencilla cambie el uso del enhebrado y su código probablemente solo funcione. Si bien el enhebrado no es perfecto en Python, es bastante bueno para hacer cosas intensivas de IO.

O bien, cree su toma de audición antes de horcar y obtenga todos los subprocesos para escuchar (llame al accept). El sistema operativo se asegurará de que solo uno de ellos obtenga la conexión. Esta es la forma en que los servidores de prefabricación generalmente se escriben.

1

Ha existido por más de 4 años, aunque requiere un poco de trabajo.

Las agallas están dando vueltas en multiprocesamiento.reducción, y los detalles de un ejemplo se pueden ver en this github gist.

0

Si crea un socket antes de bifurcar el proceso, su descriptor de archivo será heredado por los hijos.

Cuestiones relacionadas