0
# Server Classes
1
2
Socket.IO server implementations for handling multiple client connections with support for event-driven architecture, room management, session handling, and horizontal scaling through client managers.
3
4
## Capabilities
5
6
### Server
7
8
A synchronous Socket.IO server that handles multiple client connections, provides event-driven communication, room management, session storage, and integrates with various client managers for scaling.
9
10
```python { .api }
11
class Server:
12
"""
13
Synchronous Socket.IO server with full features.
14
15
Inherits from: BaseServer
16
17
Attributes:
18
manager: Client manager instance for handling connections
19
logger: Logger instance for server events
20
eio: Engine.IO server instance
21
"""
22
23
def __init__(self, client_manager=None, logger=False, serializer='default', json=None,
24
async_handlers=False, always_connect=False, namespaces=None, **kwargs):
25
"""
26
Initialize the server.
27
28
Args:
29
client_manager: Client manager instance (defaults to Manager())
30
logger (bool or Logger): Enable logging or provide custom logger
31
serializer (str): Message serializer ('default', 'pickle', 'msgpack', 'cbor')
32
json (module): Custom JSON module
33
async_handlers (bool): Allow async event handlers in sync server
34
always_connect (bool): Accept all connections without authentication
35
namespaces (list): Allowed namespaces
36
**kwargs: Additional Engine.IO server parameters
37
"""
38
39
def emit(self, event, data=None, to=None, room=None, skip_sid=None, namespace=None, callback=None):
40
"""
41
Emit an event to one or more connected clients.
42
43
Args:
44
event (str): Event name
45
data: Event data to send
46
to (str or list): Target client session ID(s)
47
room (str or list): Target room name(s)
48
skip_sid (str): Skip this client session ID
49
namespace (str): Target namespace
50
callback (callable): Callback function for response
51
52
Raises:
53
DisconnectedError: Target client not connected
54
"""
55
56
def send(self, data, to=None, room=None, skip_sid=None, namespace=None, callback=None):
57
"""
58
Send a message event to one or more connected clients.
59
60
Args:
61
data: Message data to send
62
to (str or list): Target client session ID(s)
63
room (str or list): Target room name(s)
64
skip_sid (str): Skip this client session ID
65
namespace (str): Target namespace
66
callback (callable): Callback function for response
67
68
Raises:
69
DisconnectedError: Target client not connected
70
"""
71
72
def call(self, event, data=None, to=None, sid=None, namespace=None, timeout=60):
73
"""
74
Emit an event and wait for a response from a specific client.
75
76
Args:
77
event (str): Event name
78
data: Event data to send
79
to (str): Target client session ID (deprecated, use sid)
80
sid (str): Target client session ID
81
namespace (str): Target namespace
82
timeout (int): Response timeout in seconds
83
84
Returns:
85
Response data from client
86
87
Raises:
88
TimeoutError: No response received within timeout
89
DisconnectedError: Target client not connected
90
"""
91
92
def enter_room(self, sid, room, namespace=None):
93
"""
94
Add a client to a room.
95
96
Args:
97
sid (str): Client session ID
98
room (str): Room name
99
namespace (str): Target namespace
100
101
Raises:
102
DisconnectedError: Client not connected
103
"""
104
105
def leave_room(self, sid, room, namespace=None):
106
"""
107
Remove a client from a room.
108
109
Args:
110
sid (str): Client session ID
111
room (str): Room name
112
namespace (str): Target namespace
113
114
Raises:
115
DisconnectedError: Client not connected
116
"""
117
118
def close_room(self, room, namespace=None):
119
"""
120
Remove all clients from a room and delete the room.
121
122
Args:
123
room (str): Room name
124
namespace (str): Target namespace
125
"""
126
127
def rooms(self, sid, namespace=None):
128
"""
129
Get the list of rooms a client has joined.
130
131
Args:
132
sid (str): Client session ID
133
namespace (str): Target namespace
134
135
Returns:
136
list: Room names the client has joined
137
138
Raises:
139
DisconnectedError: Client not connected
140
"""
141
142
def get_session(self, sid, namespace=None):
143
"""
144
Get the session data for a client.
145
146
Args:
147
sid (str): Client session ID
148
namespace (str): Target namespace
149
150
Returns:
151
dict: Session data
152
153
Raises:
154
DisconnectedError: Client not connected
155
"""
156
157
def save_session(self, sid, session, namespace=None):
158
"""
159
Save session data for a client.
160
161
Args:
162
sid (str): Client session ID
163
session (dict): Session data to save
164
namespace (str): Target namespace
165
166
Raises:
167
DisconnectedError: Client not connected
168
"""
169
170
def session(self, sid, namespace=None):
171
"""
172
Access client session data with context manager.
173
174
Args:
175
sid (str): Client session ID
176
namespace (str): Target namespace
177
178
Returns:
179
Context manager for session access
180
181
Raises:
182
DisconnectedError: Client not connected
183
"""
184
185
def disconnect(self, sid, namespace=None):
186
"""
187
Disconnect a client.
188
189
Args:
190
sid (str): Client session ID
191
namespace (str): Target namespace
192
193
Raises:
194
DisconnectedError: Client not connected
195
"""
196
197
def start_background_task(self, target, *args, **kwargs):
198
"""
199
Start a background task.
200
201
Args:
202
target (callable): Task function
203
*args: Task arguments
204
**kwargs: Task keyword arguments
205
206
Returns:
207
Task handle
208
"""
209
210
def sleep(self, seconds):
211
"""
212
Sleep for the given number of seconds.
213
214
Args:
215
seconds (float): Sleep duration
216
"""
217
218
def on(self, event, handler=None, namespace=None):
219
"""
220
Register an event handler.
221
222
Args:
223
event (str): Event name
224
handler (callable): Event handler function
225
namespace (str): Target namespace
226
227
Returns:
228
Decorator function if handler not provided
229
"""
230
231
def event(self, event=None, handler=None, namespace=None):
232
"""
233
Decorator to register an event handler.
234
235
Args:
236
event (str, optional): Event name (defaults to function name)
237
handler (callable): Event handler function
238
namespace (str): Target namespace
239
240
Returns:
241
Decorator function
242
"""
243
```
244
245
#### Usage Example
246
247
```python
248
import socketio
249
250
# Create server with Redis manager for scaling
251
redis_manager = socketio.RedisManager('redis://localhost:6379')
252
sio = socketio.Server(client_manager=redis_manager, logger=True)
253
254
# Event handlers
255
@sio.event
256
def connect(sid, environ):
257
print(f'Client {sid} connected')
258
# Add to default room
259
sio.enter_room(sid, 'lobby')
260
sio.emit('welcome', {'message': 'Welcome to the server!'}, room=sid)
261
262
@sio.event
263
def disconnect(sid):
264
print(f'Client {sid} disconnected')
265
266
@sio.event
267
def join_room(sid, data):
268
room = data['room']
269
sio.enter_room(sid, room)
270
sio.emit('status', {'message': f'Joined room {room}'}, room=sid)
271
sio.emit('user_joined', {'sid': sid}, room=room, skip_sid=sid)
272
273
@sio.event
274
def leave_room(sid, data):
275
room = data['room']
276
sio.leave_room(sid, room)
277
sio.emit('user_left', {'sid': sid}, room=room)
278
279
@sio.event
280
def chat_message(sid, data):
281
# Get user session data
282
with sio.session(sid) as session:
283
username = session.get('username', 'Anonymous')
284
285
room = data.get('room', 'lobby')
286
message = {
287
'username': username,
288
'message': data['message'],
289
'timestamp': time.time()
290
}
291
292
# Broadcast to room
293
sio.emit('message', message, room=room)
294
295
@sio.event
296
def set_username(sid, data):
297
# Save username in session
298
with sio.session(sid) as session:
299
session['username'] = data['username']
300
301
sio.emit('username_set', {'success': True}, room=sid)
302
303
@sio.event
304
def get_room_info(sid, data):
305
room = data['room']
306
# Use call to get response
307
try:
308
info = sio.call('room_info_request', {'room': room}, sid=sid, timeout=5)
309
return {'info': info}
310
except socketio.TimeoutError:
311
return {'error': 'Timeout getting room info'}
312
313
# Create WSGI app
314
app = socketio.WSGIApp(sio)
315
```
316
317
### AsyncServer
318
319
Asynchronous Socket.IO server that provides all the capabilities of the synchronous Server but uses coroutines for non-blocking operation in asyncio applications.
320
321
```python { .api }
322
class AsyncServer:
323
"""
324
Asynchronous Socket.IO server for asyncio.
325
326
Inherits from: BaseServer
327
328
Attributes:
329
manager: Async client manager instance
330
logger: Logger instance for server events
331
eio: Engine.IO async server instance
332
"""
333
334
def __init__(self, client_manager=None, logger=False, serializer='default', json=None,
335
always_connect=False, namespaces=None, **kwargs):
336
"""
337
Initialize the async server.
338
339
Args:
340
client_manager: Async client manager instance (defaults to AsyncManager())
341
logger (bool or Logger): Enable logging or provide custom logger
342
serializer (str): Message serializer ('default', 'pickle', 'msgpack', 'cbor')
343
json (module): Custom JSON module
344
always_connect (bool): Accept all connections without authentication
345
namespaces (list): Allowed namespaces
346
**kwargs: Additional Engine.IO server parameters
347
"""
348
349
async def emit(self, event, data=None, to=None, room=None, skip_sid=None, namespace=None, callback=None):
350
"""
351
Emit an event to one or more connected clients.
352
353
Args:
354
event (str): Event name
355
data: Event data to send
356
to (str or list): Target client session ID(s)
357
room (str or list): Target room name(s)
358
skip_sid (str): Skip this client session ID
359
namespace (str): Target namespace
360
callback (coroutine): Async callback function for response
361
362
Raises:
363
DisconnectedError: Target client not connected
364
"""
365
366
async def send(self, data, to=None, room=None, skip_sid=None, namespace=None, callback=None):
367
"""
368
Send a message event to one or more connected clients.
369
370
Args:
371
data: Message data to send
372
to (str or list): Target client session ID(s)
373
room (str or list): Target room name(s)
374
skip_sid (str): Skip this client session ID
375
namespace (str): Target namespace
376
callback (coroutine): Async callback function for response
377
378
Raises:
379
DisconnectedError: Target client not connected
380
"""
381
382
async def call(self, event, data=None, to=None, sid=None, namespace=None, timeout=60):
383
"""
384
Emit an event and wait for a response from a specific client.
385
386
Args:
387
event (str): Event name
388
data: Event data to send
389
to (str): Target client session ID (deprecated, use sid)
390
sid (str): Target client session ID
391
namespace (str): Target namespace
392
timeout (int): Response timeout in seconds
393
394
Returns:
395
Response data from client
396
397
Raises:
398
TimeoutError: No response received within timeout
399
DisconnectedError: Target client not connected
400
"""
401
402
async def enter_room(self, sid, room, namespace=None):
403
"""
404
Add a client to a room.
405
406
Args:
407
sid (str): Client session ID
408
room (str): Room name
409
namespace (str): Target namespace
410
411
Raises:
412
DisconnectedError: Client not connected
413
"""
414
415
async def leave_room(self, sid, room, namespace=None):
416
"""
417
Remove a client from a room.
418
419
Args:
420
sid (str): Client session ID
421
room (str): Room name
422
namespace (str): Target namespace
423
424
Raises:
425
DisconnectedError: Client not connected
426
"""
427
428
async def close_room(self, room, namespace=None):
429
"""
430
Remove all clients from a room and delete the room.
431
432
Args:
433
room (str): Room name
434
namespace (str): Target namespace
435
"""
436
437
async def rooms(self, sid, namespace=None):
438
"""
439
Get the list of rooms a client has joined.
440
441
Args:
442
sid (str): Client session ID
443
namespace (str): Target namespace
444
445
Returns:
446
list: Room names the client has joined
447
448
Raises:
449
DisconnectedError: Client not connected
450
"""
451
452
async def get_session(self, sid, namespace=None):
453
"""
454
Get the session data for a client.
455
456
Args:
457
sid (str): Client session ID
458
namespace (str): Target namespace
459
460
Returns:
461
dict: Session data
462
463
Raises:
464
DisconnectedError: Client not connected
465
"""
466
467
async def save_session(self, sid, session, namespace=None):
468
"""
469
Save session data for a client.
470
471
Args:
472
sid (str): Client session ID
473
session (dict): Session data to save
474
namespace (str): Target namespace
475
476
Raises:
477
DisconnectedError: Client not connected
478
"""
479
480
def session(self, sid, namespace=None):
481
"""
482
Access client session data with async context manager.
483
484
Args:
485
sid (str): Client session ID
486
namespace (str): Target namespace
487
488
Returns:
489
Async context manager for session access
490
491
Raises:
492
DisconnectedError: Client not connected
493
"""
494
495
async def disconnect(self, sid, namespace=None):
496
"""
497
Disconnect a client.
498
499
Args:
500
sid (str): Client session ID
501
namespace (str): Target namespace
502
503
Raises:
504
DisconnectedError: Client not connected
505
"""
506
507
def start_background_task(self, target, *args, **kwargs):
508
"""
509
Start a background task.
510
511
Args:
512
target (coroutine): Async task function
513
*args: Task arguments
514
**kwargs: Task keyword arguments
515
516
Returns:
517
asyncio.Task: Task handle
518
"""
519
520
async def sleep(self, seconds):
521
"""
522
Sleep for the given number of seconds.
523
524
Args:
525
seconds (float): Sleep duration
526
"""
527
528
def on(self, event, handler=None, namespace=None):
529
"""
530
Register an async event handler.
531
532
Args:
533
event (str): Event name
534
handler (coroutine): Async event handler function
535
namespace (str): Target namespace
536
537
Returns:
538
Decorator function if handler not provided
539
"""
540
541
def event(self, event=None, handler=None, namespace=None):
542
"""
543
Decorator to register an async event handler.
544
545
Args:
546
event (str, optional): Event name (defaults to function name)
547
handler (coroutine): Async event handler function
548
namespace (str): Target namespace
549
550
Returns:
551
Decorator function
552
"""
553
```
554
555
#### Usage Example
556
557
```python
558
import asyncio
559
import socketio
560
561
# Create async server with Redis manager
562
redis_manager = socketio.AsyncRedisManager('redis://localhost:6379')
563
sio = socketio.AsyncServer(client_manager=redis_manager, logger=True)
564
565
# Async event handlers
566
@sio.event
567
async def connect(sid, environ):
568
print(f'Client {sid} connected')
569
await sio.enter_room(sid, 'lobby')
570
await sio.emit('welcome', {'message': 'Welcome!'}, room=sid)
571
572
@sio.event
573
async def disconnect(sid):
574
print(f'Client {sid} disconnected')
575
576
@sio.event
577
async def join_room(sid, data):
578
room = data['room']
579
await sio.enter_room(sid, room)
580
await sio.emit('status', {'message': f'Joined {room}'}, room=sid)
581
await sio.emit('user_joined', {'sid': sid}, room=room, skip_sid=sid)
582
583
@sio.event
584
async def chat_message(sid, data):
585
# Access session asynchronously
586
async with sio.session(sid) as session:
587
username = session.get('username', 'Anonymous')
588
589
room = data.get('room', 'lobby')
590
message = {
591
'username': username,
592
'message': data['message'],
593
'timestamp': time.time()
594
}
595
596
# Broadcast to room
597
await sio.emit('message', message, room=room)
598
599
@sio.event
600
async def set_username(sid, data):
601
async with sio.session(sid) as session:
602
session['username'] = data['username']
603
604
await sio.emit('username_set', {'success': True}, room=sid)
605
606
@sio.event
607
async def get_users_in_room(sid, data):
608
room = data['room']
609
610
# Simulate async database lookup
611
await asyncio.sleep(0.1)
612
users = await get_room_users(room) # Your async function
613
614
return {'users': users}
615
616
async def get_room_users(room):
617
# Your async implementation
618
return ['user1', 'user2', 'user3']
619
620
# Create ASGI app
621
app = socketio.ASGIApp(sio)
622
623
# Run with an ASGI server like uvicorn
624
# uvicorn main:app --host 0.0.0.0 --port 5000
625
```
626
627
## Event Handler Patterns
628
629
Both Server and AsyncServer support multiple patterns for event handlers:
630
631
### Function-based Handlers
632
633
```python
634
# Synchronous server
635
sio = socketio.Server()
636
637
@sio.event
638
def connect(sid, environ):
639
print(f'Client {sid} connected')
640
641
# With custom event name
642
@sio.on('custom_event')
643
def handle_custom(sid, data):
644
print(f'Custom event from {sid}: {data}')
645
646
# Async server
647
async_sio = socketio.AsyncServer()
648
649
@async_sio.event
650
async def connect(sid, environ):
651
print(f'Client {sid} connected')
652
await async_sio.emit('welcome', room=sid)
653
```
654
655
### Class-based Handlers (Namespaces)
656
657
```python
658
# Using namespace classes (covered in detail in namespaces.md)
659
class ChatNamespace(socketio.Namespace):
660
def on_connect(self, sid, environ):
661
print(f'Client {sid} connected to chat')
662
663
def on_message(self, sid, data):
664
self.emit('response', data, room=sid)
665
666
sio.register_namespace(ChatNamespace('/chat'))
667
```
668
669
## Session Management
670
671
Both servers provide comprehensive session management:
672
673
```python
674
# Synchronous session management
675
@sio.event
676
def save_user_data(sid, data):
677
# Direct session access
678
sio.save_session(sid, {'user_id': data['user_id'], 'preferences': data['prefs']})
679
680
# Context manager (recommended)
681
with sio.session(sid) as session:
682
session['last_activity'] = time.time()
683
session['status'] = 'active'
684
685
# Asynchronous session management
686
@async_sio.event
687
async def save_user_data(sid, data):
688
# Direct session access
689
await async_sio.save_session(sid, {'user_id': data['user_id']})
690
691
# Async context manager (recommended)
692
async with async_sio.session(sid) as session:
693
session['last_activity'] = time.time()
694
session['status'] = 'active'
695
```