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 of asyncio
, Python’s standard asynchronous I/O framework,
it provides a straightforward API based on coroutines, making it easy to write
highly concurrent applications.
Installation¶
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
.
User guide¶
If you’re new to websockets
, Getting started describes usage patterns and
provides examples.
If you’ve used websockets
before and just need a quick reference, have a
look at Cheat sheet.
If you need more details, the API documentation is for you.
If you’re upgrading websockets
, check the Changelog.
Contributing¶
Bug reports, patches and suggestions welcome! Just open an issue or send a pull request.
Getting started¶
Warning
This documentation is written for Python ≥ 3.5. If you’re using Python 3.4 or 3.3, you will have to adapt the code samples.
Basic example¶
This section assumes Python ≥ 3.5. For older versions, read below.
Here’s a WebSocket server example. It reads a name from the client, sends a greeting, and closes the connection.
#!/usr/bin/env python
import asyncio
import websockets
async def hello(websocket, path):
name = await websocket.recv()
print("< {}".format(name))
greeting = "Hello {}!".format(name)
await websocket.send(greeting)
print("> {}".format(greeting))
start_server = websockets.serve(hello, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
On the server side, the handler coroutine hello
is executed once for each
WebSocket connection. The connection is automatically closed when the handler
returns.
Here’s a corresponding client example.
#!/usr/bin/env python
import asyncio
import websockets
async def hello():
async with websockets.connect('ws://localhost:8765') as websocket:
name = input("What's your name? ")
await websocket.send(name)
print("> {}".format(name))
greeting = await websocket.recv()
print("< {}".format(greeting))
asyncio.get_event_loop().run_until_complete(hello())
async
and await
aren’t available in Python < 3.5. Here’s how to adapt
the client example for older Python versions.
#!/usr/bin/env python
import asyncio
import websockets
@asyncio.coroutine
def hello():
websocket = yield from websockets.connect('ws://localhost:8765/')
try:
name = input("What's your name? ")
yield from websocket.send(name)
print("> {}".format(name))
greeting = yield from websocket.recv()
print("< {}".format(greeting))
finally:
yield from websocket.close()
asyncio.get_event_loop().run_until_complete(hello())
Browser-based example¶
Here’s an example of how to run a WebSocket server and connect from a browser.
Run this script in a console:
#!/usr/bin/env python
import asyncio
import datetime
import random
import websockets
async def time(websocket, path):
while True:
now = datetime.datetime.utcnow().isoformat() + 'Z'
await websocket.send(now)
await asyncio.sleep(random.random() * 3)
start_server = websockets.serve(time, '127.0.0.1', 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Then open this HTML file in a browser.
<!DOCTYPE html>
<html>
<head>
<title>WebSocket demo</title>
</head>
<body>
<script>
var ws = new WebSocket("ws://127.0.0.1:5678/"),
messages = document.createElement('ul');
ws.onmessage = function (event) {
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode(event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
</script>
</body>
</html>
Common patterns¶
You will usually want to process several messages during the lifetime of a connection. Therefore you must write a loop. Here are the basic patterns for building a WebSocket server.
Consumer¶
For receiving messages and passing them to a consumer
coroutine:
async def handler(websocket, path):
while True:
message = await websocket.recv()
await consumer(message)
recv()
raises a
ConnectionClosed
exception when the client
disconnects, which breaks out of the while True
loop.
Producer¶
For getting messages from a producer
coroutine and sending them:
async def handler(websocket, path):
while True:
message = await producer()
await websocket.send(message)
send()
raises a
ConnectionClosed
exception when the client
disconnects, which breaks out of the while True
loop.
Both¶
Of course, you can combine the two patterns shown above to read and write messages on the same connection.
async def handler(websocket, path):
while True:
listener_task = asyncio.ensure_future(websocket.recv())
producer_task = asyncio.ensure_future(producer())
done, pending = await asyncio.wait(
[listener_task, producer_task],
return_when=asyncio.FIRST_COMPLETED)
if listener_task in done:
message = listener_task.result()
await consumer(message)
else:
listener_task.cancel()
if producer_task in done:
message = producer_task.result()
await websocket.send(message)
else:
producer_task.cancel()
(This code looks convoluted. If you know a more straightforward solution, please let me know about it!)
Registration¶
If you need to maintain a list of currently connected clients, you must register clients when they connect and unregister them when they disconnect.
connected = set()
async def handler(websocket, path):
global connected
# Register.
connected.add(websocket)
try:
# Implement logic here.
await asyncio.wait([ws.send("Hello!") for ws in connected])
await asyncio.sleep(10)
finally:
# Unregister.
connected.remove(websocket)
This simplistic example keeps track of connected clients in memory. This only works as long as you run a single process. In a practical application, the handler may subscribe to some channels on a message broker, for example.
That’s all!¶
The design of the websockets
API was driven by simplicity.
You don’t have to worry about performing the opening or the closing handshake, answering pings, or any other behavior required by the specification.
websockets
handles all this under the hood so you don’t have to.
Python < 3.5¶
This documentation uses the await
and async
syntax introduced in
Python 3.5.
If you’re using Python 3.4 or 3.3, you must substitute:
async def ...
with:
@asyncio.coroutine
def ...
and:
await ...
with:
yield from ...
Otherwise you will encounter a SyntaxError
.
Cheat sheet¶
Server¶
- Write a coroutine that handles a single connection. It receives a websocket protocol instance and the URI path in argument.
- Create a server with
serve()
which is similar to asyncio’screate_server()
.- The server takes care of establishing connections, then lets the handler execute the application logic, and finally closes the connection after the handler exits normally or with an exception.
- You may subclass
WebSocketServerProtocol
and pass it in theklass
keyword argument for advanced customization.
Client¶
- Create a client with
connect()
which is similar to asyncio’screate_connection()
.- On Python ≥ 3.5, you can also use it as an asynchronous context manager.
- You may subclass
WebSocketClientProtocol
and pass it in theklass
keyword argument for advanced customization.
- Call
recv()
andsend()
to receive and send messages at any time. - You may
ping()
orpong()
if you wish but it isn’t needed in general. - If you aren’t using
connect()
as a context manager, callclose()
to terminate the connection.
Debugging¶
If you don’t understand what websockets
is doing, enable logging:
import logging
logger = logging.getLogger('websockets')
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())
The logs contain:
- Exceptions in the connection handler at the
ERROR
level - Exceptions in the opening or closing handshake at the
INFO
level - All frames at the
DEBUG
level — this can be very verbose
If you’re new to asyncio
, you will certainly encounter issues that are
related to asynchronous programming in general rather than to websockets
in particular. Fortunately Python’s official documentation provides advice to
develop with asyncio. Check it out: it’s invaluable!
API¶
Design¶
websockets
provides complete client and server implementations, as shown
in the getting started guide. 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¶
Server¶
The websockets.server
module defines a simple WebSocket server API.
-
websockets.server.
serve
(ws_handler, host=None, port=None, *, loop=None, klass=WebSocketServerProtocol, origins=None, subprotocols=None, extra_headers=None, **kwds)[source]¶ This coroutine creates a WebSocket server.
It’s a wrapper around the event loop’s
create_server()
method.host
,port
as well as extra keyword arguments are passed tocreate_server()
. For example, you can set thessl
keyword argument to aSSLContext
to enable TLS.ws_handler
is the WebSocket handler. It must be a coroutine accepting two arguments: aWebSocketServerProtocol
and the request URI.serve()
accepts several optional arguments:origins
defines acceptable Origin HTTP headers — include''
if the lack of an origin is acceptablesubprotocols
is a list of supported subprotocols in order of decreasing preferenceextra_headers
sets additional HTTP response headers — it can be a mapping, an iterable of (name, value) pairs, or a callable taking the request path and headers in arguments.
serve()
yields aServer
which provides:- a
close()
method that closes open connections with status code 1001 and stops accepting new connections - a
wait_closed()
coroutine that waits until closing handshakes complete and connections are closed.
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.Since there’s no useful way to propagate exceptions triggered in handlers, they’re sent to the
'websockets.server'
logger instead. Debugging is much easier if you configure logging to print them:import logging logger = logging.getLogger('websockets.server') logger.setLevel(logging.ERROR) logger.addHandler(logging.StreamHandler())
-
class
websockets.server.
WebSocketServerProtocol
(ws_handler, ws_server, *, origins=None, subprotocols=None, extra_headers=None, host=None, port=None, secure=None, timeout=10, max_size=2 ** 20, loop=None)[source]¶ Complete WebSocket server implementation as an
asyncio.Protocol
.This class inherits most of its methods from
WebSocketCommonProtocol
.For the sake of simplicity, it doesn’t rely on a full HTTP implementation. Its support for HTTP responses is very limited.
-
handshake
(origins=None, subprotocols=None, extra_headers=None)[source]¶ Perform the server side of the opening handshake.
If provided,
origins
is a list of acceptable HTTP Origin values. Include''
if the lack of an origin is acceptable.If provided,
subprotocols
is a list of supported subprotocols in order of decreasing preference.If provided,
extra_headers
sets additional HTTP response headers. It can be a mapping or an iterable of (name, value) pairs. It can also be a callable taking the request path and headers in arguments.Return the URI of the request.
-
Client¶
The websockets.client
module defines a simple WebSocket client API.
-
websockets.client.
connect
(uri, *, loop=None, klass=WebSocketClientProtocol, origin=None, subprotocols=None, extra_headers=None, **kwds)[source]¶ This coroutine connects to a WebSocket server.
It’s a wrapper around the event loop’s
create_connection()
method. Extra keyword arguments are passed tocreate_connection()
. For example, you can set thessl
keyword argument to aSSLContext
to enforce some TLS settings. When connecting to awss://
URI, if this argument isn’t provided explicitly, it’s set toTrue
, which means Python’s defaultSSLContext
is used.connect()
accepts several optional arguments:origin
sets the Origin HTTP headersubprotocols
is a list of supported subprotocols in order of decreasing preferenceextra_headers
sets additional HTTP request headers – it can be a mapping or an iterable of (name, value) pairs
connect()
yields aWebSocketClientProtocol
which can then be used to send and receive messages.It raises
InvalidURI
ifuri
is invalid andInvalidHandshake
if the handshake fails.On Python 3.5, it can be used as a asynchronous context manager. In that case, the connection is closed when exiting the context.
-
class
websockets.client.
WebSocketClientProtocol
(*, host=None, port=None, secure=None, timeout=10, max_size=2 ** 20, loop=None)[source]¶ Complete WebSocket client implementation as an
asyncio.Protocol
.This class inherits most of its methods from
WebSocketCommonProtocol
.-
handshake
(wsuri, origin=None, subprotocols=None, extra_headers=None)[source]¶ Perform the client side of the opening handshake.
If provided,
origin
sets the Origin HTTP header.If provided,
subprotocols
is a list of supported subprotocols in order of decreasing preference.If provided,
extra_headers
sets additional HTTP request headers. It must be a mapping or an iterable of (name, value) pairs.
-
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
(*, host=None, port=None, secure=None, timeout=10, max_size=2 ** 20, loop=None)[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
host
,port
andsecure
parameters are simply stored as attributes for handlers that need them.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.The
max_size
parameter enforces the maximum size for incoming messages in bytes. The default value is 1MB.None
disables the limit. If a message larger than the maximum size is received,recv()
will raiseConnectionClosed
and the connection will be closed with status code 1009.The
max_queue
parameter sets the maximum length of the queue that holds incoming messages. The default value is 32. 0 disables the limit. Messages are added to an in-memory queue when they’re received; thenrecv()
pops from that queue. In order to prevent excessive memory consumption when messages are received faster than they can be processed, the queue must be bounded. If the queue fills up, the protocol stops processing incoming data untilrecv()
is called. In this situation, various receive buffers (at least inasyncio
and in the OS) will fill up, then the TCP receive window will shrink, slowing down transmission to avoid packet loss.Since Python can use up to 4 bytes of memory to represent a single character, each websocket connection may use up to
4 * max_size * max_queue
bytes of memory to store incoming messages. By default, this is 128MB. You may want to lower the limits, depending on your application’s requirements.Once the handshake is complete, request and response HTTP headers are available:
- as a MIME
Message
in therequest_headers
andresponse_headers
attributes - as an iterable of (name, value) pairs in the
raw_request_headers
andraw_response_headers
attributes
If a subprotocol was negotiated, it’s available in the
subprotocol
attribute.Once the connection is closed, the status code is available in the
close_code
attribute and the reason inclose_reason
.-
close
(code=1000, reason='')[source]¶ This coroutine performs the closing handshake.
It waits for the other end to complete the handshake. It doesn’t do anything once the connection is closed. Thus it’s idemptotent.
It’s safe to wrap this coroutine in
ensure_future()
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,
recv()
raisesConnectionClosed
. This can happen after a normal connection closure, a protocol error or a network failure.Changed in version 3.0:
recv()
used to returnNone
instead. Refer to the changelog for details.
-
send
(data)[source]¶ This coroutine sends a message.
It sends
str
as a text frame andbytes
as a binary frame. It raises aTypeError
for other inputs.
-
ping
(data=None)[source]¶ This coroutine sends a ping.
It returns a
Future
which will be completed when the corresponding pong is received and which you may ignore if you don’t want to wait.A ping may serve as a keepalive or as a check that the remote endpoint received all messages up to this point, with
yield from ws.ping()
.By default, the ping contains four random bytes. The content may be overridden with the optional
data
argument which must be of typestr
(which will be encoded to UTF-8) orbytes
.
-
pong
(data=b'')[source]¶ This coroutine sends a pong.
An unsolicited pong may serve as a unidirectional heartbeat.
The content may be overridden with the optional
data
argument which must be of typestr
(which will be encoded to UTF-8) orbytes
.
-
local_address
¶ Local address of the connection.
This is a
(host, port)
tuple orNone
if the connection hasn’t been established yet.
-
remote_address
¶ Remote address of the connection.
This is a
(host, port)
tuple orNone
if the connection hasn’t been established yet.
-
open
¶ This property is
True
when the connection is usable.It may be used to detect disconnections but this is discouraged per the EAFP principle. When
open
isFalse
, using the connection raises aConnectionClosed
exception.
- as a MIME
Exceptions¶
-
exception
websockets.exceptions.
InvalidHandshake
[source]¶ Exception raised when a handshake request or response is invalid.
-
exception
websockets.exceptions.
InvalidOrigin
[source]¶ Exception raised when the origin in a handshake request is forbidden.
-
exception
websockets.exceptions.
InvalidState
[source]¶ Exception raised when an operation is forbidden in the current state.
-
exception
websockets.exceptions.
InvalidURI
[source]¶ Exception raised when an URI isn’t a valid websocket URI.
-
exception
websockets.exceptions.
ConnectionClosed
(code, reason)[source]¶ Exception raised when trying to read or write on a closed connection.
Provides the connection close code and reason in its
code
andreason
attributes respectively.
Low-level¶
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 an appropriate HTTP error code.
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 tocheck_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 tobuild_response()
.Otherwise it raises an
InvalidHandshake
exception and the server must return an error like 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 fromcheck_request()
.
-
websockets.handshake.
check_response
(get_header, key)[source]¶ Check a handshake response received from the server.
key
comes frombuild_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
¶ WebSocket frame.
fin
is the FIN bitopcode
is the opcodedata
is the payload data
Only these three fields are needed by higher level code. The MASK bit, payload length and masking-key are handled on the fly by
read_frame()
andwrite_frame()
.-
data
¶ Alias for field number 2
-
fin
¶ Alias for field number 0
-
opcode
¶ Alias for field number 1
-
websockets.framing.
read_frame
(reader, mask, *, max_size=None)[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 abool
telling whether the frame should be masked i.e. whether the read happens on the server side.If
max_size
is set and the payload exceeds this size in bytes,PayloadTooBig
is raised.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 theFrame
object to write.writer
is a function accepting bytes.mask
is abool
telling whether the frame should be masked i.e. 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)
whencode
is anint
andreason
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.
-
websockets.uri.
parse_uri
(uri)[source]¶ This function parses and validates a WebSocket URI.
If the URI is valid, it returns a
WebSocketURI
.Otherwise it raises an
InvalidURI
exception.
-
class
websockets.uri.
WebSocketURI
¶ WebSocket URI.
secure
is the secure flaghost
is the lower-case hostport
if the integer port, it’s always provided even if it’s the defaultresource_name
is the resource name, that is, the path and optional query
-
host
¶ Alias for field number 1
-
port
¶ Alias for field number 2
-
resource_name
¶ Alias for field number 3
-
secure
¶ Alias for field number 0
Utilities¶
The websockets.http
module provides HTTP parsing functions. They’re
merely adequate for the WebSocket handshake messages.
These functions cannot be imported from websockets
; they must be
imported from websockets.http
.
Deployment¶
The author of websockets
isn’t aware of best practices for deploying
network services based on asyncio
.
He suggests running a Python script similar to the server example, perhaps inside a supervisor if you deem it useful.
If you can share knowledge on this topic, please file an issue. Thanks!
Limitations¶
Extensions aren’t implemented. No extensions are registered at the time of writing.
The client doesn’t attempt to guarantee that there is no more than one connection to a given IP adress in a CONNECTING state.
The client doesn’t support connecting through a proxy.
Changelog¶
3.1¶
- Avoided a warning when closing a connection before the opening handshake.
- Added flow control for incoming data.
3.0¶
Warning
Version 3.0 introduces a backwards-incompatible change in the
recv()
API.
If you’re upgrading from 2.x or earlier, please read this carefully.
recv()
used to return
None
when the connection was closed. This required checking the return
value of every call:
message = await websocket.recv()
if message is None:
return
Now it raises a ConnectionClosed
exception
instead. This is more Pythonic. The previous code can be simplified to:
message = await websocket.recv()
When implementing a server, which is the more popular use case, there’s no strong reason to handle such exceptions. Let them bubble up, terminate the handler coroutine, and the server will simply ignore them.
In order to avoid stranding projects built upon an earlier version, the
previous behavior can be restored by passing legacy_recv=True
to
serve()
, connect()
,
WebSocketServerProtocol
, or
WebSocketClientProtocol
. legacy_recv
isn’t
documented in their signatures but isn’t scheduled for deprecation either.
Also:
connect()
can be used as an asynchronous context manager on Python ≥ 3.5.- Updated documentation with
await
andasync
syntax from Python 3.5. ping()
andpong()
supports data passed asstr
in addition tobytes
.- Worked around an asyncio bug affecting connection termination under load.
- Made
state_name
atttribute on protocols a public API. - Improved documentation.
2.7¶
- Added compatibility with Python 3.5.
- Refreshed documentation.
2.6¶
- Added
local_address
andremote_address
attributes on protocols. - Closed open connections with code 1001 when a server shuts down.
- Avoided TCP fragmentation of small frames.
2.5¶
- Improved documentation.
- Provided access to handshake request and response HTTP headers.
- Allowed customizing handshake request and response HTTP headers.
- Supported running on a non-default event loop.
- Returned a 403 error code instead of 400 when the request Origin isn’t allowed.
- Cancelling
recv()
no longer drops the next message. - Clarified that the closing handshake can be initiated by the client.
- Set the close status code and reason more consistently.
- Strengthened connection termination by simplifying the implementation.
- Improved tests, added tox configuration, and enforced 100% branch coverage.
2.4¶
2.3¶
- Improved compliance of close codes.
2.2¶
- Added support for limiting message size.
2.1¶
- Added
host
,port
andsecure
attributes on protocols. - Added support for providing and checking Origin.
2.0¶
Warning
Version 2.0 introduces a backwards-incompatible change in the
send()
,
ping()
, and
pong()
APIs.
If you’re upgrading from 1.x or earlier, please read this carefully.
These APIs used to be functions. Now they’re coroutines.
Instead of:
websocket.send(message)
you must now write:
await websocket.send(message)
Also:
- Added flow control for outgoing data.
1.0¶
- Initial public release.
License¶
Copyright (c) 2013-2015 Aymeric Augustin and contributors.
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.