summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/third_party/websockets/docs/intro.rst
blob: 8be700239f39d902efdfdfa7ad9895883bb9291e (plain)
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
Getting started
===============

.. currentmodule:: websockets

Requirements
------------

``websockets`` requires Python ≥ 3.6.1.

You should use the latest version of Python if possible. If you're using an
older version, be aware that for each minor version (3.x), only the latest
bugfix release (3.x.y) is officially supported.

Installation
------------

Install ``websockets`` with::

    pip install websockets

Basic example
-------------

.. _server-example:

Here's a WebSocket server example.

It reads a name from the client, sends a greeting, and closes the connection.

.. literalinclude:: ../example/server.py
    :emphasize-lines: 8,17

.. _client-example:

On the server side, ``websockets`` executes the handler coroutine ``hello``
once for each WebSocket connection. It closes the connection when the handler
coroutine returns.

Here's a corresponding WebSocket client example.

.. literalinclude:: ../example/client.py
    :emphasize-lines: 8,10

Using :func:`connect` as an asynchronous context manager ensures the
connection is closed before exiting the ``hello`` coroutine.

.. _secure-server-example:

Secure example
--------------

Secure WebSocket connections improve confidentiality and also reliability
because they reduce the risk of interference by bad proxies.

The WSS protocol is to WS what HTTPS is to HTTP: the connection is encrypted
with Transport Layer Security (TLS) — which is often referred to as Secure
Sockets Layer (SSL). WSS requires TLS certificates like HTTPS.

Here's how to adapt the server example to provide secure connections. See the
documentation of the :mod:`ssl` module for configuring the context securely.

.. literalinclude:: ../example/secure_server.py
    :emphasize-lines: 19,23-25

Here's how to adapt the client.

.. literalinclude:: ../example/secure_client.py
    :emphasize-lines: 10,15-18

This client needs a context because the server uses a self-signed certificate.

A client connecting to a secure WebSocket server with a valid certificate
(i.e. signed by a CA that your Python installation trusts) can simply pass
``ssl=True`` to :func:`connect` instead of building a context.

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:

.. literalinclude:: ../example/show_time.py

Then open this HTML file in a browser.

.. literalinclude:: ../example/show_time.html
   :language: html

Synchronization example
-----------------------

A WebSocket server can receive events from clients, process them to update the
application state, and synchronize the resulting state across clients.

Here's an example where any client can increment or decrement a counter.
Updates are propagated to all connected clients.

The concurrency model of :mod:`asyncio` guarantees that updates are
serialized.

Run this script in a console:

.. literalinclude:: ../example/counter.py

Then open this HTML file in several browsers.

.. literalinclude:: ../example/counter.html
   :language: 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 consumer_handler(websocket, path):
        async for message in websocket:
            await consumer(message)

In this example, ``consumer`` represents your business logic for processing
messages received on the WebSocket connection.

Iteration terminates when the client disconnects.

Producer
........

For getting messages from a ``producer`` coroutine and sending them::

    async def producer_handler(websocket, path):
        while True:
            message = await producer()
            await websocket.send(message)

In this example, ``producer`` represents your business logic for generating
messages to send on the WebSocket connection.

:meth:`~protocol.WebSocketCommonProtocol.send` raises a
:exc:`~exceptions.ConnectionClosed` exception when the client disconnects,
which breaks out of the ``while True`` loop.

Both
....

You can read and write messages on the same connection by combining the two
patterns shown above and running the two tasks in parallel::

    async def handler(websocket, path):
        consumer_task = asyncio.ensure_future(
            consumer_handler(websocket, path))
        producer_task = asyncio.ensure_future(
            producer_handler(websocket, path))
        done, pending = await asyncio.wait(
            [consumer_task, producer_task],
            return_when=asyncio.FIRST_COMPLETED,
        )
        for task in pending:
            task.cancel()

Registration
............

As shown in the synchronization example above, if you need to maintain a list
of currently connected clients, you must register them when they connect and
unregister them when they disconnect.

::

    connected = set()

    async def handler(websocket, path):
        # 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.

One more thing...
-----------------

``websockets`` provides an interactive client::

    $ python -m websockets wss://echo.websocket.org/