sansio.rst (11235B)
1 Integrate the Sans-I/O layer 2 ============================ 3 4 .. currentmodule:: websockets 5 6 This guide explains how to integrate the `Sans-I/O`_ layer of websockets to 7 add support for WebSocket in another library. 8 9 .. _Sans-I/O: https://sans-io.readthedocs.io/ 10 11 As a prerequisite, you should decide how you will handle network I/O and 12 asynchronous control flow. 13 14 Your integration layer will provide an API for the application on one side, 15 will talk to the network on the other side, and will rely on websockets to 16 implement the protocol in the middle. 17 18 .. image:: ../topics/data-flow.svg 19 :align: center 20 21 Opening a connection 22 -------------------- 23 24 Client-side 25 ........... 26 27 If you're building a client, parse the URI you'd like to connect to:: 28 29 from websockets.uri import parse_uri 30 31 wsuri = parse_uri("ws://example.com/") 32 33 Open a TCP connection to ``(wsuri.host, wsuri.port)`` and perform a TLS 34 handshake if ``wsuri.secure`` is :obj:`True`. 35 36 Initialize a :class:`~client.ClientProtocol`:: 37 38 from websockets.client import ClientProtocol 39 40 protocol = ClientProtocol(wsuri) 41 42 Create a WebSocket handshake request 43 with :meth:`~client.ClientProtocol.connect` and send it 44 with :meth:`~client.ClientProtocol.send_request`:: 45 46 request = protocol.connect() 47 protocol.send_request(request) 48 49 Then, call :meth:`~protocol.Protocol.data_to_send` and send its output to 50 the network, as described in `Send data`_ below. 51 52 Once you receive enough data, as explained in `Receive data`_ below, the first 53 event returned by :meth:`~protocol.Protocol.events_received` is the WebSocket 54 handshake response. 55 56 When the handshake fails, the reason is available in 57 :attr:`~client.ClientProtocol.handshake_exc`:: 58 59 if protocol.handshake_exc is not None: 60 raise protocol.handshake_exc 61 62 Else, the WebSocket connection is open. 63 64 A WebSocket client API usually performs the handshake then returns a wrapper 65 around the network socket and the :class:`~client.ClientProtocol`. 66 67 Server-side 68 ........... 69 70 If you're building a server, accept network connections from clients and 71 perform a TLS handshake if desired. 72 73 For each connection, initialize a :class:`~server.ServerProtocol`:: 74 75 from websockets.server import ServerProtocol 76 77 protocol = ServerProtocol() 78 79 Once you receive enough data, as explained in `Receive data`_ below, the first 80 event returned by :meth:`~protocol.Protocol.events_received` is the WebSocket 81 handshake request. 82 83 Create a WebSocket handshake response 84 with :meth:`~server.ServerProtocol.accept` and send it 85 with :meth:`~server.ServerProtocol.send_response`:: 86 87 response = protocol.accept(request) 88 protocol.send_response(response) 89 90 Alternatively, you may reject the WebSocket handshake and return an HTTP 91 response with :meth:`~server.ServerProtocol.reject`:: 92 93 response = protocol.reject(status, explanation) 94 protocol.send_response(response) 95 96 Then, call :meth:`~protocol.Protocol.data_to_send` and send its output to 97 the network, as described in `Send data`_ below. 98 99 Even when you call :meth:`~server.ServerProtocol.accept`, the WebSocket 100 handshake may fail if the request is incorrect or unsupported. 101 102 When the handshake fails, the reason is available in 103 :attr:`~server.ServerProtocol.handshake_exc`:: 104 105 if protocol.handshake_exc is not None: 106 raise protocol.handshake_exc 107 108 Else, the WebSocket connection is open. 109 110 A WebSocket server API usually builds a wrapper around the network socket and 111 the :class:`~server.ServerProtocol`. Then it invokes a connection handler that 112 accepts the wrapper in argument. 113 114 It may also provide a way to close all connections and to shut down the server 115 gracefully. 116 117 Going forwards, this guide focuses on handling an individual connection. 118 119 From the network to the application 120 ----------------------------------- 121 122 Go through the five steps below until you reach the end of the data stream. 123 124 Receive data 125 ............ 126 127 When receiving data from the network, feed it to the protocol's 128 :meth:`~protocol.Protocol.receive_data` method. 129 130 When reaching the end of the data stream, call the protocol's 131 :meth:`~protocol.Protocol.receive_eof` method. 132 133 For example, if ``sock`` is a :obj:`~socket.socket`:: 134 135 try: 136 data = sock.recv(65536) 137 except OSError: # socket closed 138 data = b"" 139 if data: 140 protocol.receive_data(data) 141 else: 142 protocol.receive_eof() 143 144 These methods aren't expected to raise exceptions — unless you call them again 145 after calling :meth:`~protocol.Protocol.receive_eof`, which is an error. 146 (If you get an exception, please file a bug!) 147 148 Send data 149 ......... 150 151 Then, call :meth:`~protocol.Protocol.data_to_send` and send its output to 152 the network:: 153 154 for data in protocol.data_to_send(): 155 if data: 156 sock.sendall(data) 157 else: 158 sock.shutdown(socket.SHUT_WR) 159 160 The empty bytestring signals the end of the data stream. When you see it, you 161 must half-close the TCP connection. 162 163 Sending data right after receiving data is necessary because websockets 164 responds to ping frames, close frames, and incorrect inputs automatically. 165 166 Expect TCP connection to close 167 .............................. 168 169 Closing a WebSocket connection normally involves a two-way WebSocket closing 170 handshake. Then, regardless of whether the closure is normal or abnormal, the 171 server starts the four-way TCP closing handshake. If the network fails at the 172 wrong point, you can end up waiting until the TCP timeout, which is very long. 173 174 To prevent dangling TCP connections when you expect the end of the data stream 175 but you never reach it, call :meth:`~protocol.Protocol.close_expected` 176 and, if it returns :obj:`True`, schedule closing the TCP connection after a 177 short timeout:: 178 179 # start a new execution thread to run this code 180 sleep(10) 181 sock.close() # does nothing if the socket is already closed 182 183 If the connection is still open when the timeout elapses, closing the socket 184 makes the execution thread that reads from the socket reach the end of the 185 data stream, possibly with an exception. 186 187 Close TCP connection 188 .................... 189 190 If you called :meth:`~protocol.Protocol.receive_eof`, close the TCP 191 connection now. This is a clean closure because the receive buffer is empty. 192 193 After :meth:`~protocol.Protocol.receive_eof` signals the end of the read 194 stream, :meth:`~protocol.Protocol.data_to_send` always signals the end of 195 the write stream, unless it already ended. So, at this point, the TCP 196 connection is already half-closed. The only reason for closing it now is to 197 release resources related to the socket. 198 199 Now you can exit the loop relaying data from the network to the application. 200 201 Receive events 202 .............. 203 204 Finally, call :meth:`~protocol.Protocol.events_received` to obtain events 205 parsed from the data provided to :meth:`~protocol.Protocol.receive_data`:: 206 207 events = connection.events_received() 208 209 The first event will be the WebSocket opening handshake request or response. 210 See `Opening a connection`_ above for details. 211 212 All later events are WebSocket frames. There are two types of frames: 213 214 * Data frames contain messages transferred over the WebSocket connections. You 215 should provide them to the application. See `Fragmentation`_ below for 216 how to reassemble messages from frames. 217 * Control frames provide information about the connection's state. The main 218 use case is to expose an abstraction over ping and pong to the application. 219 Keep in mind that websockets responds to ping frames and close frames 220 automatically. Don't duplicate this functionality! 221 222 From the application to the network 223 ----------------------------------- 224 225 The connection object provides one method for each type of WebSocket frame. 226 227 For sending a data frame: 228 229 * :meth:`~protocol.Protocol.send_continuation` 230 * :meth:`~protocol.Protocol.send_text` 231 * :meth:`~protocol.Protocol.send_binary` 232 233 These methods raise :exc:`~exceptions.ProtocolError` if you don't set 234 the :attr:`FIN <websockets.frames.Frame.fin>` bit correctly in fragmented 235 messages. 236 237 For sending a control frame: 238 239 * :meth:`~protocol.Protocol.send_close` 240 * :meth:`~protocol.Protocol.send_ping` 241 * :meth:`~protocol.Protocol.send_pong` 242 243 :meth:`~protocol.Protocol.send_close` initiates the closing handshake. 244 See `Closing a connection`_ below for details. 245 246 If you encounter an unrecoverable error and you must fail the WebSocket 247 connection, call :meth:`~protocol.Protocol.fail`. 248 249 After any of the above, call :meth:`~protocol.Protocol.data_to_send` and 250 send its output to the network, as shown in `Send data`_ above. 251 252 If you called :meth:`~protocol.Protocol.send_close` 253 or :meth:`~protocol.Protocol.fail`, you expect the end of the data 254 stream. You should follow the process described in `Close TCP connection`_ 255 above in order to prevent dangling TCP connections. 256 257 Closing a connection 258 -------------------- 259 260 Under normal circumstances, when a server wants to close the TCP connection: 261 262 * it closes the write side; 263 * it reads until the end of the stream, because it expects the client to close 264 the read side; 265 * it closes the socket. 266 267 When a client wants to close the TCP connection: 268 269 * it reads until the end of the stream, because it expects the server to close 270 the read side; 271 * it closes the write side; 272 * it closes the socket. 273 274 Applying the rules described earlier in this document gives the intended 275 result. As a reminder, the rules are: 276 277 * When :meth:`~protocol.Protocol.data_to_send` returns the empty 278 bytestring, close the write side of the TCP connection. 279 * When you reach the end of the read stream, close the TCP connection. 280 * When :meth:`~protocol.Protocol.close_expected` returns :obj:`True`, if 281 you don't reach the end of the read stream quickly, close the TCP connection. 282 283 Fragmentation 284 ------------- 285 286 WebSocket messages may be fragmented. Since this is a protocol-level concern, 287 you may choose to reassemble fragmented messages before handing them over to 288 the application. 289 290 To reassemble a message, read data frames until you get a frame where 291 the :attr:`FIN <websockets.frames.Frame.fin>` bit is set, then concatenate 292 the payloads of all frames. 293 294 You will never receive an inconsistent sequence of frames because websockets 295 raises a :exc:`~exceptions.ProtocolError` and fails the connection when this 296 happens. However, you may receive an incomplete sequence if the connection 297 drops in the middle of a fragmented message. 298 299 Tips 300 ---- 301 302 Serialize operations 303 .................... 304 305 The Sans-I/O layer expects to run sequentially. If your interact with it from 306 multiple threads or coroutines, you must ensure correct serialization. This 307 should happen automatically in a cooperative multitasking environment. 308 309 However, you still have to make sure you don't break this property by 310 accident. For example, serialize writes to the network 311 when :meth:`~protocol.Protocol.data_to_send` returns multiple values to 312 prevent concurrent writes from interleaving incorrectly. 313 314 Avoid buffers 315 ............. 316 317 The Sans-I/O layer doesn't do any buffering. It makes events available in 318 :meth:`~protocol.Protocol.events_received` as soon as they're received. 319 320 You should make incoming messages available to the application immediately and 321 stop further processing until the application fetches them. This will usually 322 result in the best performance.