Los Frijoles Los Frijoles - 1 month ago 16
Python Question

Send socket object to forked running process (multiprocessing.Queue)

I am learning to use HTML5 WebSockets and as part of that I am writing a server in Python so I can know the nitty gritty of how they work. I created one the other day that worked pretty well, but I wanted to expand it so it would support multiple endpoints with each endpoint being a different "service" which can handle websocket clients.

At the moment, my implementation works with spawning processes and such (I am using multiprocessing instead of threading since I read that threading isn't really multithreading in CPython and that's what I think I am using (default install on Ubuntu 12.04)), but I am having trouble sending received client sockets to the service processes.

Here is how I send them (this runs in a loop):

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' is a socket listening for incoming connections. The handshake method takes care of validating their request and determining which service process to put the client into. 'response' is the http response to send, 'close' is True if there was an error, and 'service' is a class which inherits from multiprocessing.Queue. WebSocktes.WebSocketClient is where my sending and receiving implementation is stored and it basically functions as a wrapper for a socket.

'clientConnQueue' is created like so:

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 is a multiprocessing.Manager()

The error I get when I try to place a client in the clientConnQueue is as follows:

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


I then get a broken pipe error on the receiving side.

I got the same error when I was using a multiprocessing.Queue to send the connection and I thought that changing it to a queue created by a manager would fix the problem. However, it seems to do the exact same implementation.

Clearly this isn't the way one is supposed to send something like this to a running process, so what is the proper way to be sending non-serializable objects to a process?

Answer

Pass socket to another process is not a trivial thing. Look, for example, this question: Can I open a socket and pass it to another process in Linux

Anyway, OS processes or threads is not what you really want for implement websocket server, because of large memory overhead. Look at smth with nonblocking sockets... eg, Tornado http://www.tornadoweb.org/documentation/websocket.html