server Package¶
cherrypyserver
Module¶
WebSocket within CherryPy is a tricky bit since CherryPy is a threaded server which would choke quickly if each thread of the server were kept attached to a long living connection that WebSocket expects.
In order to work around this constraint, we take some advantage of some internals of CherryPy as well as the introspection Python provides.
Basically, when the WebSocket handshake is complete, we take over the socket and let CherryPy take back the thread that was associated with the upgrade request.
These operations require a bit of work at various levels of the CherryPy framework but this module takes care of them and from your application’s perspective, this is abstracted.
Here are the various utilities provided by this module:
- WebSocketTool: The tool is in charge to perform the
- HTTP upgrade and detach the socket from CherryPy. It runs at various hook points of the request’s processing. Enable that tool at any path you wish to handle as a WebSocket handler.
- WebSocketPlugin: The plugin tracks the instanciated web socket handlers.
- It also cleans out websocket handler which connection have been closed down. The websocket connection then runs in its own thread that this plugin manages.
Simple usage example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import EchoWebSocket
cherrypy.config.update({'server.socket_port': 9000})
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()
class Root(object):
@cherrypy.expose
def index(self):
return 'some HTML with a websocket javascript connection'
@cherrypy.expose
def ws(self):
pass
cherrypy.quickstart(Root(), '/', config={'/ws': {'tools.websocket.on': True,
'tools.websocket.handler_cls': EchoWebSocket}})
|
Note that you can set the handler class on per-path basis, meaning you could also dynamically change the class based on other envrionmental settings (is the user authenticated for ex).
-
class
ws4py.server.cherrypyserver.
WebSocketTool
[source]¶ Bases:
cherrypy._cptools.Tool
-
upgrade
(protocols=None, extensions=None, version=(8, 13), handler_cls=<class 'ws4py.websocket.WebSocket'>, heartbeat_freq=None)[source]¶ Performs the upgrade of the connection to the WebSocket protocol.
The provided protocols may be a list of WebSocket protocols supported by the instance of the tool.
When no list is provided and no protocol is either during the upgrade, then the protocol parameter is not taken into account. On the other hand, if the protocol from the handshake isn’t part of the provided list, the upgrade fails immediatly.
-
geventserver
Module¶
wsgirefserver
Module¶
Add WebSocket support to the built-in WSGI server
provided by the wsgiref
. This is clearly not
meant to be a production server so please consider this
only for testing purpose.
Mostly, this module overrides bits and pieces of the built-in classes so that it supports the WebSocket workflow.
from wsgiref.simple_server import make_server
from ws4py.websocket import EchoWebSocket
from ws4py.server.wsgirefserver import WSGIServer, WebSocketWSGIRequestHandler
from ws4py.server.wsgiutils import WebSocketWSGIApplication
server = make_server('', 9000, server_class=WSGIServer,
handler_class=WebSocketWSGIRequestHandler,
app=WebSocketWSGIApplication(handler_cls=EchoWebSocket))
server.initialize_websockets_manager()
server.serve_forever()
Note
For some reason this server may fail against autobahntestsuite.
-
class
ws4py.server.wsgirefserver.
WebSocketWSGIHandler
(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)[source]¶
-
class
ws4py.server.wsgirefserver.
WebSocketWSGIRequestHandler
(request, client_address, server)[source]¶ Bases:
wsgiref.simple_server.WSGIRequestHandler
-
class
WebSocketWSGIHandler
(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)¶ Bases:
wsgiref.handlers.SimpleHandler
-
finish_response
()¶ Completes the response and performs the following tasks:
- Remove the ‘ws4py.socket’ and ‘ws4py.websocket’ environ keys.
- Attach the returned websocket, if any, to the WSGI server
using its
link_websocket_to_server
method.
-
setup_environ
()¶ Setup the environ dictionary and add the ‘ws4py.socket’ key. Its associated value is the real socket underlying socket.
-
-
class
-
class
ws4py.server.wsgirefserver.
WSGIServer
(server_address, RequestHandlerClass, bind_and_activate=True)[source]¶ Bases:
wsgiref.simple_server.WSGIServer
Constructor. May be extended, do not override.
-
initialize_websockets_manager
()[source]¶ Call thos to start the underlying websockets manager. Make sure to call it once your server is created.
-
wsgitutils
Module¶
This module provides a WSGI application suitable for a WSGI server such as gevent or wsgiref for instance.
PEP 333 couldn’t foresee a protocol such as WebSockets but luckily the way the initial protocol upgrade was designed means that we can fit the handshake in a WSGI flow.
The handshake validates the request against some internal or user-provided values and fails the request if the validation doesn’t complete.
On success, the provided WebSocket subclass is instanciated and stored into the ‘ws4py.websocket’ environ key so that the WSGI server can handle it.
The WSGI application returns an empty iterable since there is little value to return some content within the response to the handshake.
A server wishing to support WebSocket via ws4py should:
- Provide the real socket object to ws4py through the ‘ws4py.socket’ environ key. We can’t use ‘wsgi.input’ as it may be wrapper to the socket we wouldn’t know how to extract the socket from.
- Look for the ‘ws4py.websocket’ key in the environ
when the application has returned and probably attach
it to a
ws4py.manager.WebSocketManager
instance so that the websocket runs its life. - Remove the ‘ws4py.websocket’ and ‘ws4py.socket’ environ keys once the application has returned. No need for these keys to persist.
- Not close the underlying socket otherwise, well, your websocket will also shutdown.
Warning
The WSGI application sets the ‘Upgrade’ header response as specified by RFC 6455. This is not tolerated by PEP 333 since it’s a hop-by-hop header. We expect most servers won’t mind.
-
class
ws4py.server.wsgiutils.
WebSocketWSGIApplication
(protocols=None, extensions=None, handler_cls=<class 'ws4py.websocket.WebSocket'>)[source]¶ Bases:
object
WSGI application usable to complete the upgrade handshake by validating the requested protocols and extensions as well as the websocket version.
If the upgrade validates, the handler_cls class is instanciated and stored inside the WSGI environ under the ‘ws4py.websocket’ key to make it available to the WSGI handler.