0
# Synchronous Client Operations
1
2
Threading-based synchronous WebSocket client functionality for connecting to WebSocket servers using blocking operations, suitable for traditional Python applications that don't use asyncio.
3
4
## Core Imports
5
6
```python
7
from websockets.sync.client import connect, unix_connect, ClientConnection
8
```
9
10
## Capabilities
11
12
### Connection Functions
13
14
Create synchronous WebSocket client connections with blocking operations for environments where asyncio is not suitable or preferred.
15
16
```python { .api }
17
def connect(
18
uri: str,
19
*,
20
# TCP/TLS
21
sock: socket.socket | None = None,
22
ssl: ssl.SSLContext | None = None,
23
server_hostname: str | None = None,
24
# WebSocket
25
origin: Origin | None = None,
26
extensions: Sequence[ClientExtensionFactory] | None = None,
27
subprotocols: Sequence[Subprotocol] | None = None,
28
compression: str | None = "deflate",
29
# HTTP
30
additional_headers: HeadersLike | None = None,
31
user_agent_header: str | None = USER_AGENT,
32
proxy: str | Literal[True] | None = True,
33
proxy_ssl: ssl.SSLContext | None = None,
34
proxy_server_hostname: str | None = None,
35
# Timeouts
36
open_timeout: float | None = 10,
37
ping_interval: float | None = 20,
38
ping_timeout: float | None = 20,
39
close_timeout: float | None = 10,
40
# Limits
41
max_size: int | None = 2**20,
42
max_queue: int | None | tuple[int | None, int | None] = 16,
43
# Logging
44
logger: LoggerLike | None = None,
45
# Escape hatch for advanced customization
46
create_connection: type[ClientConnection] | None = None,
47
**kwargs: Any
48
) -> ClientConnection:
49
"""
50
Connect to a WebSocket server synchronously.
51
52
Parameters:
53
- uri: WebSocket URI (ws:// or wss://)
54
- sock: Preexisting TCP socket (overrides host/port from URI)
55
- ssl: SSL context for TLS configuration
56
- server_hostname: Host name for TLS handshake (overrides URI hostname)
57
- origin: Value of Origin header for servers that require it
58
- extensions: List of supported extensions in negotiation order
59
- subprotocols: List of supported subprotocols in preference order
60
- compression: Compression mode ("deflate" or None)
61
- additional_headers: Extra HTTP headers for handshake
62
- user_agent_header: Custom User-Agent header
63
- proxy: Proxy configuration (True for auto-detect, str for URL, None to disable)
64
- proxy_ssl: SSL context for proxy connection
65
- proxy_server_hostname: Server hostname for proxy TLS handshake
66
- open_timeout: Timeout for connection establishment (seconds)
67
- ping_interval: Interval between ping frames (seconds)
68
- ping_timeout: Timeout for ping/pong exchange (seconds)
69
- close_timeout: Timeout for connection closure (seconds)
70
- max_size: Maximum message size (bytes)
71
- max_queue: Maximum number of queued messages (int or tuple)
72
- logger: Logger instance for connection logging
73
- create_connection: Custom connection class factory
74
75
Returns:
76
ClientConnection: Synchronous WebSocket connection
77
78
Raises:
79
- InvalidURI: If URI format is invalid
80
- InvalidHandshake: If handshake fails
81
- ConnectionClosedError: If connection fails
82
"""
83
84
def unix_connect(
85
path: str | None = None,
86
uri: str | None = None,
87
**kwargs: Any
88
) -> ClientConnection:
89
"""
90
Connect to a WebSocket server over Unix domain socket synchronously.
91
92
Parameters:
93
- path: Unix socket path for connection (mutually exclusive with uri)
94
- uri: WebSocket URI with unix:// scheme (mutually exclusive with path)
95
- **kwargs: Same keyword arguments as connect()
96
97
Returns:
98
ClientConnection: Synchronous WebSocket connection
99
100
Note:
101
Only available on Unix-like systems (Linux, macOS).
102
Accepts the same keyword arguments as connect().
103
"""
104
```
105
106
### Client Connection Management
107
108
The synchronous ClientConnection class provides blocking operations for WebSocket communication.
109
110
```python { .api }
111
class ClientConnection:
112
"""Synchronous WebSocket client connection."""
113
114
@property
115
def closed(self) -> bool:
116
"""Check if connection is closed."""
117
118
@property
119
def local_address(self) -> Tuple[str, int]:
120
"""Get local socket address."""
121
122
@property
123
def remote_address(self) -> Tuple[str, int]:
124
"""Get remote socket address."""
125
126
@property
127
def subprotocol(self) -> Subprotocol | None:
128
"""Get negotiated subprotocol."""
129
130
def send(self, message: Data, timeout: float = None) -> None:
131
"""
132
Send a message to the WebSocket server.
133
134
Parameters:
135
- message: Text (str) or binary (bytes) message to send
136
- timeout: Optional timeout for send operation (seconds)
137
138
Raises:
139
- ConnectionClosed: If connection is closed
140
- TimeoutError: If timeout is exceeded
141
"""
142
143
def recv(self, timeout: float = None) -> Data:
144
"""
145
Receive a message from the WebSocket server.
146
147
Parameters:
148
- timeout: Optional timeout for receive operation (seconds)
149
150
Returns:
151
str | bytes: Received message (text or binary)
152
153
Raises:
154
- ConnectionClosed: If connection is closed
155
- TimeoutError: If timeout is exceeded
156
"""
157
158
def ping(self, data: bytes = b"", timeout: float = None) -> float:
159
"""
160
Send a ping frame and wait for pong response.
161
162
Parameters:
163
- data: Optional payload for ping frame
164
- timeout: Optional timeout for ping/pong exchange (seconds)
165
166
Returns:
167
float: Round-trip time in seconds
168
169
Raises:
170
- ConnectionClosed: If connection is closed
171
- TimeoutError: If timeout is exceeded
172
"""
173
174
def pong(self, data: bytes = b"") -> None:
175
"""
176
Send a pong frame.
177
178
Parameters:
179
- data: Payload for pong frame
180
181
Raises:
182
- ConnectionClosed: If connection is closed
183
"""
184
185
def close(self, code: int = 1000, reason: str = "") -> None:
186
"""
187
Close the WebSocket connection.
188
189
Parameters:
190
- code: Close code (default 1000 for normal closure)
191
- reason: Human-readable close reason
192
193
Raises:
194
- ProtocolError: If code is invalid
195
"""
196
197
# Context manager support
198
def __enter__(self) -> ClientConnection:
199
"""Enter context manager."""
200
return self
201
202
def __exit__(self, exc_type, exc_value, traceback) -> None:
203
"""Exit context manager and close connection."""
204
self.close()
205
206
# Iterator support for receiving messages
207
def __iter__(self) -> Iterator[Data]:
208
"""Return iterator for receiving messages."""
209
return self
210
211
def __next__(self) -> Data:
212
"""Get next message from iterator."""
213
try:
214
return self.recv()
215
except ConnectionClosed:
216
raise StopIteration
217
```
218
219
## Usage Examples
220
221
### Basic Synchronous Client
222
223
```python
224
from websockets.sync import connect
225
226
def basic_client():
227
"""Simple synchronous WebSocket client."""
228
with connect("ws://localhost:8765") as websocket:
229
# Send a message
230
websocket.send("Hello, Server!")
231
232
# Receive response
233
response = websocket.recv()
234
print(f"Server response: {response}")
235
236
# Run the client
237
basic_client()
238
```
239
240
### Client with Timeout Handling
241
242
```python
243
from websockets.sync import connect
244
from websockets import ConnectionClosed, TimeoutError
245
246
def timeout_client():
247
"""Client with timeout handling."""
248
try:
249
with connect(
250
"ws://localhost:8765",
251
open_timeout=5,
252
close_timeout=3
253
) as websocket:
254
255
# Send with timeout
256
websocket.send("Hello with timeout!", timeout=2.0)
257
258
# Receive with timeout
259
try:
260
response = websocket.recv(timeout=5.0)
261
print(f"Response: {response}")
262
except TimeoutError:
263
print("No response received within timeout")
264
265
# Test connection with ping
266
try:
267
latency = websocket.ping(timeout=3.0)
268
print(f"Connection latency: {latency:.3f}s")
269
except TimeoutError:
270
print("Ping timeout - connection may be stale")
271
272
except ConnectionClosed as e:
273
print(f"Connection closed: {e}")
274
except Exception as e:
275
print(f"Connection error: {e}")
276
277
timeout_client()
278
```
279
280
### Message Iterator Client
281
282
```python
283
from websockets.sync import connect
284
from websockets import ConnectionClosed
285
286
def iterator_client():
287
"""Client using message iteration."""
288
try:
289
with connect("ws://localhost:8765") as websocket:
290
# Send initial message
291
websocket.send("Start streaming")
292
293
# Iterate over received messages
294
for message in websocket:
295
print(f"Received: {message}")
296
297
# Send acknowledgment
298
websocket.send("ACK")
299
300
# Break on specific message
301
if message.lower() == "stop":
302
break
303
304
except ConnectionClosed:
305
print("Connection closed by server")
306
307
iterator_client()
308
```
309
310
### Multi-threaded Client Example
311
312
```python
313
import threading
314
import time
315
from websockets.sync import connect
316
from websockets import ConnectionClosed
317
318
def worker_thread(thread_id: int, uri: str):
319
"""Worker thread with independent WebSocket connection."""
320
try:
321
with connect(uri) as websocket:
322
print(f"Thread {thread_id}: Connected")
323
324
# Send periodic messages
325
for i in range(5):
326
message = f"Thread {thread_id}, Message {i}"
327
websocket.send(message)
328
329
try:
330
response = websocket.recv(timeout=2.0)
331
print(f"Thread {thread_id}: {response}")
332
except Exception as e:
333
print(f"Thread {thread_id}: Error - {e}")
334
335
time.sleep(1)
336
337
except ConnectionClosed as e:
338
print(f"Thread {thread_id}: Connection closed - {e}")
339
340
def multi_threaded_client():
341
"""Example using multiple threads with sync connections."""
342
threads = []
343
uri = "ws://localhost:8765"
344
345
# Create multiple worker threads
346
for i in range(3):
347
thread = threading.Thread(
348
target=worker_thread,
349
args=(i, uri)
350
)
351
threads.append(thread)
352
thread.start()
353
354
# Wait for all threads to complete
355
for thread in threads:
356
thread.join()
357
358
print("All threads completed")
359
360
multi_threaded_client()
361
```
362
363
### Client with Custom Headers and Authentication
364
365
```python
366
from websockets.sync import connect
367
import base64
368
369
def authenticated_client():
370
"""Client with custom headers and authentication."""
371
# Prepare authentication header
372
credentials = base64.b64encode(b"username:password").decode()
373
374
headers = {
375
"Authorization": f"Basic {credentials}",
376
"X-Client-Version": "1.0",
377
"X-Client-Type": "Python-Sync"
378
}
379
380
try:
381
with connect(
382
"ws://localhost:8765",
383
additional_headers=headers,
384
subprotocols=["chat", "notifications"],
385
compression="deflate"
386
) as websocket:
387
388
print(f"Connected with subprotocol: {websocket.subprotocol}")
389
390
# Send authentication verification
391
websocket.send("VERIFY_AUTH")
392
auth_response = websocket.recv()
393
394
if auth_response == "AUTH_OK":
395
print("Authentication successful")
396
397
# Normal operation
398
websocket.send("GET_STATUS")
399
status = websocket.recv()
400
print(f"Status: {status}")
401
else:
402
print("Authentication failed")
403
404
except Exception as e:
405
print(f"Authentication error: {e}")
406
407
authenticated_client()
408
```
409
410
### Unix Domain Socket Client
411
412
```python
413
from websockets.sync import unix_connect
414
415
def unix_client():
416
"""Client connecting via Unix domain socket."""
417
try:
418
with unix_connect("/tmp/websocket.sock") as websocket:
419
print("Connected via Unix socket")
420
421
# Send message
422
websocket.send("Hello via Unix socket!")
423
424
# Receive response
425
response = websocket.recv()
426
print(f"Response: {response}")
427
428
except FileNotFoundError:
429
print("Unix socket not found - is the server running?")
430
except Exception as e:
431
print(f"Unix socket error: {e}")
432
433
unix_client()
434
```
435
436
### Error Handling and Reconnection
437
438
```python
439
import time
440
from websockets.sync import connect
441
from websockets import ConnectionClosed, InvalidURI
442
443
def robust_client_with_reconnect():
444
"""Client with automatic reconnection logic."""
445
uri = "ws://localhost:8765"
446
max_retries = 5
447
retry_delay = 2
448
449
for attempt in range(max_retries):
450
try:
451
print(f"Connection attempt {attempt + 1}")
452
453
with connect(uri, open_timeout=5) as websocket:
454
print("Connected successfully")
455
456
# Normal operation
457
try:
458
while True:
459
websocket.send("ping")
460
response = websocket.recv(timeout=10)
461
462
if response == "pong":
463
print("Connection healthy")
464
time.sleep(5)
465
else:
466
print(f"Unexpected response: {response}")
467
468
except ConnectionClosed:
469
print("Connection lost")
470
break
471
except KeyboardInterrupt:
472
print("Interrupted by user")
473
return
474
475
except (ConnectionClosed, InvalidURI) as e:
476
print(f"Connection failed: {e}")
477
478
if attempt < max_retries - 1:
479
print(f"Retrying in {retry_delay} seconds...")
480
time.sleep(retry_delay)
481
retry_delay *= 2 # Exponential backoff
482
else:
483
print("Max retries exceeded")
484
break
485
486
except Exception as e:
487
print(f"Unexpected error: {e}")
488
break
489
490
robust_client_with_reconnect()
491
```