0
# WebSocket Support
1
2
Full WebSocket protocol implementation for real-time, bidirectional communication between client and server. Supports both server-side handlers and client connections.
3
4
## Capabilities
5
6
### WebSocket Handler
7
8
Server-side WebSocket handler for processing incoming WebSocket connections, messages, and managing connection lifecycle.
9
10
```python { .api }
11
class WebSocketHandler(tornado.web.RequestHandler):
12
"""WebSocket request handler for server-side connections."""
13
14
def open(self, *args, **kwargs):
15
"""
16
Called when WebSocket connection is opened.
17
18
Args:
19
*args: URL path arguments
20
**kwargs: URL keyword arguments
21
"""
22
23
def on_message(self, message):
24
"""
25
Called when message is received from client.
26
27
Args:
28
message: Message content (str or bytes)
29
"""
30
31
def on_close(self):
32
"""Called when WebSocket connection is closed."""
33
34
def write_message(self, message, binary: bool = False):
35
"""
36
Send message to client.
37
38
Args:
39
message: Message to send (str or bytes)
40
binary: Whether message is binary
41
42
Raises:
43
WebSocketClosedError: If connection is closed
44
"""
45
46
def close(self, code: int = None, reason: str = None):
47
"""
48
Close WebSocket connection.
49
50
Args:
51
code: Close status code
52
reason: Close reason string
53
"""
54
55
def check_origin(self, origin: str) -> bool:
56
"""
57
Check if request origin is allowed.
58
59
Args:
60
origin: Request origin header
61
62
Returns:
63
True if origin is allowed, False otherwise
64
"""
65
66
def get_compression_options(self):
67
"""Get WebSocket compression options."""
68
69
def set_nodelay(self, value: bool):
70
"""Enable/disable Nagle's algorithm."""
71
72
def ping(self, data: bytes = b"") -> Future:
73
"""
74
Send ping frame to client.
75
76
Args:
77
data: Ping payload data
78
79
Returns:
80
Future that resolves when pong is received
81
"""
82
83
def on_pong(self, data: bytes):
84
"""
85
Called when pong frame is received.
86
87
Args:
88
data: Pong payload data
89
"""
90
```
91
92
### WebSocket Client
93
94
Client-side WebSocket connection for connecting to WebSocket servers and managing client connections.
95
96
```python { .api }
97
def websocket_connect(url: str, callback=None, connect_timeout: float = None, on_message_callback=None, compression_options=None, ping_interval: float = None, ping_timeout: float = None, max_message_size: int = None, subprotocols=None) -> Future:
98
"""
99
Connect to WebSocket server.
100
101
Args:
102
url: WebSocket URL (ws:// or wss://)
103
callback: Callback function (if not using async/await)
104
connect_timeout: Connection timeout in seconds
105
on_message_callback: Callback for incoming messages
106
compression_options: Compression configuration
107
ping_interval: Ping interval in seconds
108
ping_timeout: Ping timeout in seconds
109
max_message_size: Maximum message size in bytes
110
subprotocols: List of supported subprotocols
111
112
Returns:
113
Future resolving to WebSocketClientConnection
114
115
Usage:
116
conn = await websocket_connect("ws://example.com/websocket")
117
await conn.write_message("Hello")
118
msg = await conn.read_message()
119
conn.close()
120
"""
121
122
class WebSocketClientConnection:
123
"""Client-side WebSocket connection."""
124
125
def write_message(self, message, binary: bool = False) -> Future:
126
"""
127
Send message to server.
128
129
Args:
130
message: Message to send (str or bytes)
131
binary: Whether message is binary
132
133
Returns:
134
Future that resolves when message is sent
135
"""
136
137
def read_message(self, callback=None) -> Future:
138
"""
139
Read next message from server.
140
141
Args:
142
callback: Callback function (if not using async/await)
143
144
Returns:
145
Future resolving to message string/bytes or None if closed
146
"""
147
148
def close(self, code: int = None, reason: str = None):
149
"""
150
Close WebSocket connection.
151
152
Args:
153
code: Close status code
154
reason: Close reason string
155
"""
156
157
def ping(self, data: bytes = b"") -> Future:
158
"""
159
Send ping frame to server.
160
161
Args:
162
data: Ping payload data
163
164
Returns:
165
Future that resolves when pong is received
166
"""
167
168
@property
169
def protocol(self) -> WebSocketProtocol:
170
"""Get WebSocket protocol handler."""
171
```
172
173
### WebSocket Protocol
174
175
Low-level WebSocket protocol implementation handling frame parsing, masking, and protocol compliance.
176
177
```python { .api }
178
class WebSocketProtocol:
179
"""Abstract WebSocket protocol handler."""
180
181
def __init__(self, handler, mask_outgoing: bool = False, compression_options=None):
182
"""
183
Initialize WebSocket protocol.
184
185
Args:
186
handler: WebSocket handler object
187
mask_outgoing: Whether to mask outgoing frames
188
compression_options: Compression configuration
189
"""
190
191
def accept_connection(self, handler):
192
"""Accept WebSocket connection."""
193
194
def write_message(self, message, binary: bool = False, locked: bool = True):
195
"""Write WebSocket message."""
196
197
def read_message(self, callback):
198
"""Read WebSocket message."""
199
200
def close(self, code: int = None, reason: str = None):
201
"""Close WebSocket connection."""
202
203
def ping(self, data: bytes) -> Future:
204
"""Send ping frame."""
205
206
def pong(self, data: bytes):
207
"""Send pong frame."""
208
209
class WebSocketProtocol13(WebSocketProtocol):
210
"""WebSocket protocol version 13 implementation."""
211
212
def __init__(self, handler, mask_outgoing: bool = False, compression_options=None):
213
"""Initialize WebSocket protocol v13."""
214
215
def compute_accept_value(self, key: str) -> str:
216
"""Compute WebSocket accept value from key."""
217
218
def challenge_response(self, challenge: str) -> str:
219
"""Generate challenge response for client."""
220
```
221
222
### WebSocket Utilities
223
224
Utility functions for WebSocket protocol handling, frame processing, and connection management.
225
226
```python { .api }
227
def websocket_connect(url: str, **kwargs):
228
"""Create WebSocket client connection."""
229
230
def encode_username_password(username: str, password: str) -> str:
231
"""Encode credentials for WebSocket authentication."""
232
233
class WebSocketMask:
234
"""WebSocket frame masking utilities."""
235
236
@staticmethod
237
def mask(mask: bytes, data: bytes) -> bytes:
238
"""Apply WebSocket mask to data."""
239
```
240
241
## WebSocket Usage Examples
242
243
### Basic WebSocket Server
244
245
```python
246
import tornado.ioloop
247
import tornado.web
248
import tornado.websocket
249
250
class EchoWebSocket(tornado.websocket.WebSocketHandler):
251
def open(self):
252
print("WebSocket opened")
253
254
def on_message(self, message):
255
print(f"Received: {message}")
256
self.write_message(f"Echo: {message}")
257
258
def on_close(self):
259
print("WebSocket closed")
260
261
def check_origin(self, origin):
262
# Allow connections from any origin
263
return True
264
265
app = tornado.web.Application([
266
(r"/websocket", EchoWebSocket),
267
])
268
269
if __name__ == "__main__":
270
app.listen(8888)
271
print("WebSocket server started on ws://localhost:8888/websocket")
272
tornado.ioloop.IOLoop.current().start()
273
```
274
275
### WebSocket Client
276
277
```python
278
import asyncio
279
import tornado.websocket
280
281
async def websocket_client():
282
# Connect to WebSocket server
283
conn = await tornado.websocket.websocket_connect("ws://localhost:8888/websocket")
284
285
try:
286
# Send message
287
await conn.write_message("Hello WebSocket!")
288
289
# Read response
290
msg = await conn.read_message()
291
print(f"Received: {msg}")
292
293
finally:
294
# Close connection
295
conn.close()
296
297
if __name__ == "__main__":
298
asyncio.run(websocket_client())
299
```
300
301
### Chat Room WebSocket Server
302
303
```python
304
import tornado.ioloop
305
import tornado.web
306
import tornado.websocket
307
import json
308
309
class ChatWebSocket(tornado.websocket.WebSocketHandler):
310
clients = set()
311
312
def open(self):
313
print("Client connected")
314
ChatWebSocket.clients.add(self)
315
316
def on_message(self, message):
317
try:
318
data = json.loads(message)
319
# Broadcast message to all connected clients
320
for client in ChatWebSocket.clients:
321
if client != self: # Don't send back to sender
322
client.write_message(json.dumps({
323
'user': data.get('user', 'Anonymous'),
324
'message': data.get('message', ''),
325
'type': 'message'
326
}))
327
except json.JSONDecodeError:
328
self.write_message(json.dumps({
329
'error': 'Invalid JSON format',
330
'type': 'error'
331
}))
332
333
def on_close(self):
334
print("Client disconnected")
335
ChatWebSocket.clients.discard(self)
336
337
def check_origin(self, origin):
338
return True
339
340
app = tornado.web.Application([
341
(r"/chat", ChatWebSocket),
342
])
343
```
344
345
## Types
346
347
```python { .api }
348
# WebSocket message type
349
WebSocketMessage = Union[str, bytes, None]
350
351
# Close code type
352
WebSocketCloseCode = int
353
354
# Compression options type
355
CompressionOptions = Dict[str, Any]
356
357
# Subprotocols type
358
SubProtocols = List[str]
359
360
# WebSocket handler type
361
WebSocketHandlerType = Type[WebSocketHandler]
362
```
363
364
## Constants
365
366
```python { .api }
367
# WebSocket close codes
368
WS_CLOSE_NORMAL = 1000
369
WS_CLOSE_GOING_AWAY = 1001
370
WS_CLOSE_PROTOCOL_ERROR = 1002
371
WS_CLOSE_UNSUPPORTED_DATA = 1003
372
WS_CLOSE_NO_STATUS = 1005
373
WS_CLOSE_ABNORMAL = 1006
374
WS_CLOSE_INVALID_DATA = 1007
375
WS_CLOSE_POLICY_VIOLATION = 1008
376
WS_CLOSE_MESSAGE_TOO_BIG = 1009
377
WS_CLOSE_MISSING_EXTENSION = 1010
378
WS_CLOSE_INTERNAL_ERROR = 1011
379
380
# WebSocket opcodes
381
WS_OPCODE_CONTINUATION = 0x0
382
WS_OPCODE_TEXT = 0x1
383
WS_OPCODE_BINARY = 0x2
384
WS_OPCODE_CLOSE = 0x8
385
WS_OPCODE_PING = 0x9
386
WS_OPCODE_PONG = 0xa
387
```
388
389
## Exceptions
390
391
```python { .api }
392
class WebSocketError(Exception):
393
"""Base exception for WebSocket errors."""
394
395
class WebSocketClosedError(WebSocketError):
396
"""Exception raised when connection is closed."""
397
398
def __init__(self, real_error=None):
399
"""
400
Initialize WebSocket closed error.
401
402
Args:
403
real_error: Underlying error that caused closure
404
"""
405
```