WebSockets¶
websockets
is a library for developing WebSocket servers and clients in
Python. It implements RFC 6455 with a focus on correctness and simplicity.
It passes the Autobahn Testsuite.
Built on top on Python’s asynchronous I/O support introduced in PEP 3156, it provides an API based on coroutines, making it easy to write highly concurrent applications.
Installation is as simple as pip install websockets
. It requires Python ≥
3.4 or Python 3.3 with the asyncio
module, which is available with pip
install asyncio
or in the Tulip repository.
Bug reports, patches and suggestions welcome! Just open an issue or send a pull request.
Example¶
Here’s a WebSocket server example. It reads a name from the client and sends a message.
#!/usr/bin/env python
import asyncio
import websockets
@asyncio.coroutine
def hello(websocket, uri):
name = yield from websocket.recv()
print("< {}".format(name))
greeting = "Hello {}!".format(name)
print("> {}".format(greeting))
yield from websocket.send(greeting)
start_server = websockets.serve(hello, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Note
The handler function, hello
, is executed once for each WebSocket
connection. The connection is automatically closed when the handler
returns. If you want to process several messages in the same connection,
you must write a loop, most likely with websocket.open
.
Here’s a corresponding client example.
#!/usr/bin/env python
import asyncio
import websockets
@asyncio.coroutine
def hello():
websocket = yield from websockets.connect('ws://localhost:8765/')
name = input("What's your name? ")
yield from websocket.send(name)
print("> {}".format(name))
greeting = yield from websocket.recv()
print("< {}".format(greeting))
asyncio.get_event_loop().run_until_complete(hello())
Design¶
websockets
provides complete client and server implementations, as shown in
the examples above. These functions are built on top of low-level APIs
reflecting the two phases of the WebSocket protocol:
- An opening handshake, in the form of an HTTP Upgrade request;
- Data transfer, as framed messages, ending with a closing handshake.
The first phase is designed to integrate with existing HTTP software.
websockets
provides functions to build and validate the request and
response headers.
The second phase is the core of the WebSocket protocol. websockets
provides a standalone implementation on top of asyncio
with a very simple
API.
For convenience, public APIs can be imported directly from the
websockets
package, unless noted otherwise. Anything that isn’t listed
in this document is a private API.
High-level API¶
Server¶
The websockets.server
module defines a simple WebSocket server API.
-
websockets.server.
serve
(ws_handler, host=None, port=None, *, klass=WebSocketServerProtocol, **kwds)[source]¶ This coroutine creates a WebSocket server.
It’s a thin wrapper around the event loop’s
create_server
method.host
,port
as well as extra keyword arguments are passed tocreate_server
.It returns a
Server
object with aclose
method to stop the server.ws_handler is the WebSocket handler. It must be a coroutine accepting two arguments: a
WebSocketServerProtocol
and the request URI. The host and port arguments and other keyword arguments are passed tocreate_server
.Whenever a client connects, the server accepts the connection, creates a
WebSocketServerProtocol
, performs the opening handshake, and delegates to the WebSocket handler. Once the handler completes, the server performs the closing handshake and closes the connection.
-
class
websockets.server.
WebSocketServerProtocol
(self, ws_handler, timeout=10)[source]¶ Complete WebSocket server implementation as an asyncio protocol.
This class inherits most of its methods from
WebSocketCommonProtocol
.For the sake of simplicity, this protocol doesn’t inherit a proper HTTP implementation, and it doesn’t send appropriate HTTP responses when something goes wrong.
Client¶
The websockets.client
module defines a simple WebSocket client API.
-
websockets.client.
connect
(uri, *, klass=WebSocketClientProtocol, **kwds)[source]¶ This coroutine connects to a WebSocket server.
It’s a thin wrapper around the event loop’s
create_connection
method. Extra keyword arguments are passed tocreate_server
.It returns a
WebSocketClientProtocol
which can then be used to send and receive messages.It raises
InvalidURI
if uri is invalid andInvalidHandshake
if the handshake fails.Clients shouldn’t close the WebSocket connection. Instead, they should wait until the server performs the closing handshake by yielding from the protocol’s
worker
attribute.connect()
implements the sequence called “Establish a WebSocket Connection” in RFC 6455, except for the requirement that “there MUST be no more than one connection in a CONNECTING state.”
-
class
websockets.client.
WebSocketClientProtocol
(self, timeout=10)[source]¶ Complete WebSocket client implementation as an asyncio protocol.
This class inherits most of its methods from
WebSocketCommonProtocol
.
Shared¶
The websockets.protocol
module handles WebSocket control and data
frames as specified in sections 4 to 8 of RFC 6455.
-
class
websockets.protocol.
WebSocketCommonProtocol
(self, timeout=10)[source]¶ This class implements common parts of the WebSocket protocol.
It assumes that the WebSocket connection is established. The handshake is managed in subclasses such as
WebSocketServerProtocol
andWebSocketClientProtocol
.It runs a task that stores incoming data frames in a queue and deals with control frames automatically. It sends outgoing data frames and performs the closing handshake.
The timeout parameter defines the maximum wait time in seconds for completing the closing handshake and, only on the client side, for terminating the TCP connection.
close()
will complete in at most this time on the server side and twice this time on the client side.Once the connection is closed, the status code is available in the
close_code
attribute and the reason inclose_reason
.-
open
¶ This property is
True
when the connection is usable.It may be used to handle disconnections gracefully.
-
close
(code=1000, reason='')[source]¶ This coroutine performs the closing handshake.
This is the expected way to terminate a connection on the server side.
It waits for the other end to complete the handshake. It doesn’t do anything once the connection is closed.
It’s usually safe to wrap this coroutine in
asyncio.async()
since errors during connection termination aren’t particularly useful.
-
recv
()[source]¶ This coroutine receives the next message.
It returns a
str
for a text frame andbytes
for a binary frame.When the end of the message stream is reached, or when a protocol error occurs,
recv()
returnsNone
, indicating that the connection is closed.
-
send
(data)[source]¶ This coroutine sends a message.
It sends a
str
as a text frame andbytes
as a binary frame.It raises a
TypeError
for other inputs andInvalidState
once the connection is closed.
-
Low-level API¶
Exceptions¶
-
exception
websockets.exceptions.
InvalidHandshake
[source]¶ Exception raised when a handshake request or response is invalid.
Opening handshake¶
The websockets.handshake
module deals with the WebSocket opening
handshake according to section 4 of RFC 6455.
It provides functions to implement the handshake with any existing HTTP library. You must pass to these functions:
- A set_header function accepting a header name and a header value,
- A get_header function accepting a header name and returning the header value.
The inputs and outputs of get_header and set_header are str
objects containing only ASCII characters.
Some checks cannot be performed because they depend too much on the context; instead, they’re documented below.
To accept a connection, a server must:
- Read the request, check that the method is GET, and check the headers with
check_request()
, - Send a 101 response to the client with the headers created by
build_response()
if the request is valid; otherwise, send a 400.
To open a connection, a client must:
- Send a GET request to the server with the headers created by
build_request()
, - Read the response, check that the status code is 101, and check the headers
with
check_response()
.
-
websockets.handshake.
build_request
(set_header)[source]¶ Build a handshake request to send to the server.
Return the key which must be passed to
check_response()
.
-
websockets.handshake.
check_request
(get_header)[source]¶ Check a handshake request received from the client.
If the handshake is valid, this function returns the key which must be passed to
build_response()
.Otherwise, it raises an
InvalidHandshake
exception and the server must return an error, usually 400 Bad Request.This function doesn’t verify that the request is an HTTP/1.1 or higher GET request and doesn’t perform Host and Origin checks. These controls are usually performed earlier in the HTTP request handling code. They’re the responsibility of the caller.
-
websockets.handshake.
build_response
(set_header, key)[source]¶ Build a handshake response to send to the client.
key comes from
check_request()
.
-
websockets.handshake.
check_response
(get_header, key)[source]¶ Check a handshake response received from the server.
key comes from
build_request()
.If the handshake is valid, this function returns
None
.Otherwise, it raises an
InvalidHandshake
exception.This function doesn’t verify that the response is an HTTP/1.1 or higher response with a 101 status code. These controls are the responsibility of the caller.
Data transfer¶
The websockets.framing
module implements data framing as specified in
section 5 of RFC 6455.
It deals with a single frame at a time. Anything that depends on the sequence
of frames is implemented in websockets.protocol
.
-
class
websockets.framing.
Frame
(fin, opcode, data)¶ -
data
¶ Alias for field number 2
-
fin
¶ Alias for field number 0
-
opcode
¶ Alias for field number 1
-
-
websockets.framing.
read_frame
(reader, mask)[source]¶ Read a WebSocket frame and return a
Frame
object.reader is a coroutine taking an integer argument and reading exactly this number of bytes, unless the end of file is reached.
mask is a
bool
telling whether the frame should be masked, ie. whether the read happens on the server side.This function validates the frame before returning it and raises
WebSocketProtocolError
if it contains incorrect values.
-
websockets.framing.
write_frame
(frame, writer, mask)[source]¶ Write a WebSocket frame.
frame is the
Frame
object to write.writer is a function accepting bytes.
mask is a
bool
telling whether the frame should be masked, ie. whether the write happens on the client side.This function validates the frame before sending it and raises
WebSocketProtocolError
if it contains incorrect values.
-
websockets.framing.
parse_close
(data)[source]¶ Parse the data in a close frame.
Return (code, reason) when code is an
int
and reason astr
.Raise
WebSocketProtocolError
orUnicodeDecodeError
if the data is invalid.
-
websockets.framing.
serialize_close
(code, reason)[source]¶ Serialize the data for a close frame.
This is the reverse of
parse_close()
.
URI parser¶
The websockets.uri
module implements parsing of WebSocket URIs
according to section 3 of RFC 6455.
Utilities¶
The websockets.http
module provides HTTP parsing functions. They’re
merely adequate for the WebSocket handshake messages. They’re used by the
sample client and servers.
These functions cannot be imported from websockets
; they must be
imported from websockets.http
.
Limitations¶
Subprotocols and Extensions aren’t implemented. Few subprotocols and no extensions are registered at the time of writing.
License¶
Copyright (c) 2013-2014 Aymeric Augustin.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of websockets nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.