Managing a pool of WebSockets

ws4py provides a ws4py.manager.WebSocketManager class that takes care of ws4py.websocket.WebSocket instances once they the HTTP upgrade handshake has been performed.

The manager is not compulsory but makes it simpler to track and let them run in your application’s process.

When you add(websocket) a websocket to the manager, the file-descriptor is registered with the manager’s poller and the opened() method on is called.

Polling

The manager uses a polling mechanism to dispatch on socket incoming events. Two pollers are implemented, one using the traditionnal select and another one based on select.epoll which is used only if available on the system.

The polling is executed in its own thread, it keeps looping until the manager stop() method.

On every loop, the poller is called to poll for all registered file-descriptors. If any one of them is ready, we retrieve the websocket using that descriptor and, if the websocket is not yet terminated, we call its once method so that the incoming bytes are processed.

If the processing fails in anyway, the manager terminates the websocket and remove it from itself.

Client example

Below is a simple example on how to start 2000 clients against a single server.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from ws4py.client import WebSocketBaseClient
from ws4py.manager import WebSocketManager
from ws4py import format_addresses, configure_logger

logger = configure_logger()

m = WebSocketManager()

class EchoClient(WebSocketBaseClient):
    def handshake_ok(self):
        logger.info("Opening %s" % format_addresses(self))
        m.add(self)

    def received_message(self, msg):
        logger.info(str(msg))

if __name__ == '__main__':
    import time

    try:
        m.start()
        for i in range(2000):
            client = EchoClient('ws://localhost:9000/ws')
            client.connect()

        logger.info("%d clients are connected" % i)

        while True:
            for ws in m.websockets.itervalues():
                if not ws.terminated:
                   break
            else:
                break
            time.sleep(3)
    except KeyboardInterrupt:
        m.close_all()
        m.stop()
        m.join()

Once those are created against the echo_cherrypy_server example for instance, point your browser to http://localhost:9000/ and enter a message. It will be broadcasted to all connected peers.

When a peer is closed, its connection is automatically removed from the manager so you should never need to explicitely remove it.

Note

The CherryPy and wsgiref servers internally use a manager to handle connected websockets. The gevent server relies only on a greenlet group instead.