Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 783
Los Frijoles Avatar asked May 28 '12 18:05

Los Frijoles


2 Answers

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

like image 72
seriyPS Avatar answered Nov 14 '22 00:11

seriyPS


It's been around for 4+ years, though takes a little bit of work.

The guts are hanging around in multiprocessing.reduction, and the details of an example can be seen in this github gist.

like image 38
Josiah Avatar answered Nov 14 '22 00:11

Josiah