0
# Connection Management
1
2
Core connection establishment, state management, and lifecycle control for both client and server WebSocket connections. This module provides the main high-level interface for WebSocket operations.
3
4
## Capabilities
5
6
### Main Connection Class
7
8
The primary interface for WebSocket connections, handling both client and server modes with automatic handshake management.
9
10
```python { .api }
11
class WSConnection:
12
"""
13
Represents the local end of a WebSocket connection to a remote peer.
14
"""
15
def __init__(self, connection_type: ConnectionType) -> None:
16
"""
17
Constructor for WebSocket connection.
18
19
Args:
20
connection_type: Controls whether the library behaves as a client or server
21
"""
22
23
@property
24
def state(self) -> ConnectionState:
25
"""
26
Returns the current connection state.
27
28
Returns:
29
Current connection state
30
"""
31
32
def send(self, event: Event) -> bytes:
33
"""
34
Generate network data for the specified event.
35
36
When you want to communicate with a WebSocket peer, construct an event
37
and pass it to this method. This method will return the bytes that you
38
should send to the peer.
39
40
Args:
41
event: The event to generate data for
42
43
Returns:
44
The data to send to the peer
45
"""
46
47
def receive_data(self, data: Optional[bytes]) -> None:
48
"""
49
Feed network data into the connection instance.
50
51
After calling this method, you should call events() to see if the
52
received data triggered any new events.
53
54
Args:
55
data: Data received from remote peer, or None to signal connection closed
56
"""
57
58
def events(self) -> Generator[Event, None, None]:
59
"""
60
A generator that yields pending events.
61
62
Each event is an instance of a subclass of Event.
63
64
Yields:
65
Event objects representing WebSocket protocol actions
66
"""
67
68
def initiate_upgrade_connection(self, headers: Headers, path: Union[bytes, str]) -> None:
69
"""
70
Initiate an upgrade connection (server only).
71
72
This should be used if the request has already been received and parsed.
73
74
Args:
75
headers: HTTP headers represented as a list of 2-tuples
76
path: A URL path
77
78
Raises:
79
LocalProtocolError: If called on a client connection
80
"""
81
```
82
83
### Connection Types
84
85
Enumeration controlling whether the connection acts as a client or server.
86
87
```python { .api }
88
class ConnectionType(Enum):
89
"""An enumeration of connection types."""
90
91
CLIENT = 1 # This connection will act as client and talk to a remote server
92
SERVER = 2 # This connection will act as server and wait for client connections
93
94
# Convenience constants
95
CLIENT = ConnectionType.CLIENT
96
SERVER = ConnectionType.SERVER
97
```
98
99
### Connection States
100
101
Enumeration representing the various states of a WebSocket connection lifecycle.
102
103
```python { .api }
104
class ConnectionState(Enum):
105
"""
106
RFC 6455, Section 4 - Opening Handshake states.
107
"""
108
109
CONNECTING = 0 # The opening handshake is in progress
110
OPEN = 1 # The opening handshake is complete
111
REMOTE_CLOSING = 2 # The remote WebSocket has initiated a connection close
112
LOCAL_CLOSING = 3 # The local WebSocket has initiated a connection close
113
CLOSED = 4 # The closing handshake has completed
114
REJECTING = 5 # The connection was rejected during the opening handshake
115
```
116
117
### Low-Level Connection Class
118
119
Direct WebSocket connection object for advanced use cases requiring more control.
120
121
```python { .api }
122
class Connection:
123
"""
124
A low-level WebSocket connection object.
125
126
This wraps WebSocket frame protocol functionality for exchanging messages
127
and control frames after the handshake is complete.
128
"""
129
130
def __init__(
131
self,
132
connection_type: ConnectionType,
133
extensions: Optional[List[Extension]] = None,
134
trailing_data: bytes = b"",
135
) -> None:
136
"""
137
Initialize a low-level connection.
138
139
Args:
140
connection_type: Whether this is a client or server connection
141
extensions: List of negotiated extensions
142
trailing_data: Any trailing data from handshake
143
"""
144
145
@property
146
def state(self) -> ConnectionState:
147
"""Get the current connection state."""
148
149
def send(self, event: Event) -> bytes:
150
"""
151
Send an event and return bytes to transmit.
152
153
Args:
154
event: Event to send (Message, Ping, Pong, or CloseConnection)
155
156
Returns:
157
Bytes to send over the network
158
159
Raises:
160
LocalProtocolError: If event cannot be sent in current state
161
"""
162
163
def receive_data(self, data: Optional[bytes]) -> None:
164
"""
165
Pass received data to the connection for handling.
166
167
Args:
168
data: Data received from remote peer, or None if connection closed
169
170
Raises:
171
LocalProtocolError: If connection is already closed
172
"""
173
174
def events(self) -> Generator[Event, None, None]:
175
"""
176
Return a generator that provides events generated by protocol activity.
177
178
Yields:
179
Event subclasses representing WebSocket protocol actions
180
"""
181
```
182
183
### HTTP Handshake Handler
184
185
Low-level HTTP/1.1 handshake implementation for WebSocket upgrade negotiation.
186
187
```python { .api }
188
class H11Handshake:
189
"""
190
A Handshake implementation for HTTP/1.1 connections.
191
192
Handles the WebSocket upgrade handshake process using the h11 HTTP library,
193
managing the transition from HTTP to WebSocket protocol.
194
"""
195
196
def __init__(self, connection_type: ConnectionType) -> None:
197
"""
198
Initialize handshake handler.
199
200
Args:
201
connection_type: Whether this is a client or server handshake
202
"""
203
204
@property
205
def state(self) -> ConnectionState:
206
"""Get the current handshake state."""
207
208
@property
209
def connection(self) -> Optional[Connection]:
210
"""
211
Return the established connection.
212
213
Returns the WebSocket connection after successful handshake,
214
or None if handshake is not yet complete.
215
216
Returns:
217
Connection object or None
218
"""
219
220
def initiate_upgrade_connection(
221
self, headers: Headers, path: Union[bytes, str]
222
) -> None:
223
"""
224
Initiate an upgrade connection (server only).
225
226
Used when the HTTP request has already been received and parsed
227
externally, allowing the handshake to process the upgrade.
228
229
Args:
230
headers: HTTP headers as list of 2-tuples
231
path: URL path from the request
232
233
Raises:
234
LocalProtocolError: If called on a client connection
235
"""
236
237
def send(self, event: Event) -> bytes:
238
"""
239
Send an event and return bytes to transmit.
240
241
Args:
242
event: Event to send during handshake
243
244
Returns:
245
Bytes to send over the network
246
247
Raises:
248
LocalProtocolError: If event is not valid for current state
249
"""
250
251
def receive_data(self, data: Optional[bytes]) -> None:
252
"""
253
Process received handshake data.
254
255
Args:
256
data: Raw bytes from network, or None if connection closed
257
"""
258
259
def events(self) -> Generator[Event, None, None]:
260
"""
261
Generator yielding handshake events.
262
263
Yields:
264
Event objects representing handshake progress
265
"""
266
```
267
268
## Usage Examples
269
270
### Client Connection Example
271
272
```python
273
from wsproto import WSConnection, ConnectionType
274
from wsproto.events import Request, AcceptConnection, TextMessage, CloseConnection
275
import socket
276
277
# Create client connection
278
ws = WSConnection(ConnectionType.CLIENT)
279
280
# Connect to server
281
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
282
sock.connect(('echo.websocket.org', 80))
283
284
# Send handshake
285
request_data = ws.send(Request(host='echo.websocket.org', target='/'))
286
sock.send(request_data)
287
288
# Receive handshake response
289
response_data = sock.recv(4096)
290
ws.receive_data(response_data)
291
292
# Process events
293
for event in ws.events():
294
if isinstance(event, AcceptConnection):
295
print("Connected!")
296
# Send a message
297
message_data = ws.send(TextMessage(data="Hello WebSocket!"))
298
sock.send(message_data)
299
elif isinstance(event, TextMessage):
300
print(f"Received: {event.data}")
301
# Close connection
302
close_data = ws.send(CloseConnection(code=1000, reason="Done"))
303
sock.send(close_data)
304
305
sock.close()
306
```
307
308
### Server Connection Example
309
310
```python
311
from wsproto import WSConnection, ConnectionType
312
from wsproto.events import Request, AcceptConnection, TextMessage, CloseConnection
313
import socket
314
315
# Create server socket
316
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
317
server_sock.bind(('localhost', 8765))
318
server_sock.listen(1)
319
320
client_sock, addr = server_sock.accept()
321
322
# Create server connection
323
ws = WSConnection(ConnectionType.SERVER)
324
325
# Receive handshake
326
request_data = client_sock.recv(4096)
327
ws.receive_data(request_data)
328
329
# Process events
330
for event in ws.events():
331
if isinstance(event, Request):
332
print(f"WebSocket request for {event.target}")
333
# Accept connection
334
response_data = ws.send(AcceptConnection())
335
client_sock.send(response_data)
336
elif isinstance(event, TextMessage):
337
print(f"Received: {event.data}")
338
# Echo message back
339
echo_data = ws.send(TextMessage(data=f"Echo: {event.data}"))
340
client_sock.send(echo_data)
341
elif isinstance(event, CloseConnection):
342
print("Connection closing")
343
# Respond to close
344
close_data = ws.send(event.response())
345
client_sock.send(close_data)
346
break
347
348
client_sock.close()
349
server_sock.close()
350
```
351
352
### State Management Example
353
354
```python
355
from wsproto import WSConnection, ConnectionType
356
from wsproto.connection import ConnectionState
357
358
ws = WSConnection(ConnectionType.CLIENT)
359
360
# Check initial state
361
print(f"Initial state: {ws.state}") # ConnectionState.CONNECTING
362
363
# After successful handshake
364
# ... handshake process ...
365
print(f"After handshake: {ws.state}") # ConnectionState.OPEN
366
367
# After initiating close
368
# ... close process ...
369
print(f"After close: {ws.state}") # ConnectionState.LOCAL_CLOSING or CLOSED
370
```