0
# Asynchronous Client
1
2
Asyncio-based Engine.IO client for connecting to servers from async Python applications. Provides the same functionality as the synchronous client but with full async/await support for modern async applications.
3
4
## Capabilities
5
6
### Client Initialization
7
8
Create and configure an asynchronous Engine.IO client with the same configuration options as the synchronous client.
9
10
```python { .api }
11
class AsyncClient:
12
def __init__(
13
self,
14
logger=False,
15
json=None,
16
request_timeout=5,
17
http_session=None,
18
ssl_verify=True,
19
handle_sigint=True,
20
websocket_extra_options=None,
21
timestamp_requests=True
22
):
23
"""
24
Initialize asynchronous Engine.IO client.
25
26
Args:
27
logger (bool|Logger): Logging configuration, default False
28
json (module): Alternative JSON module
29
request_timeout (int): Request timeout in seconds, default 5
30
http_session (aiohttp.ClientSession): HTTP session object for requests
31
ssl_verify (bool): Verify SSL certificates, default True
32
handle_sigint (bool): Handle SIGINT automatically, default True
33
websocket_extra_options (dict): Extra WebSocket client options
34
timestamp_requests (bool): Add timestamps to requests, default True
35
"""
36
```
37
38
### Async Connection Management
39
40
Establish connections to Engine.IO servers asynchronously with coroutine-based methods.
41
42
```python { .api }
43
async def connect(self, url, headers=None, transports=None, engineio_path='engine.io'):
44
"""
45
Connect to an Engine.IO server (coroutine).
46
47
Args:
48
url (str): Server URL (e.g., 'http://localhost:5000')
49
headers (dict, optional): Additional HTTP headers for connection
50
transports (list, optional): Allowed transports ['polling', 'websocket']
51
engineio_path (str): Engine.IO endpoint path, default 'engine.io'
52
53
Raises:
54
ConnectionError: If connection fails
55
ValueError: If URL is invalid or transports unsupported
56
"""
57
58
async def wait(self):
59
"""
60
Wait until the connection ends (coroutine).
61
62
This method suspends the current coroutine until the client disconnects
63
or the connection is lost.
64
"""
65
66
async def disconnect(self, abort=False, reason=None):
67
"""
68
Disconnect from the server (coroutine).
69
70
Args:
71
abort (bool): Abort connection immediately without graceful shutdown
72
reason (str, optional): Reason for disconnection
73
"""
74
```
75
76
### Async Message Communication
77
78
Send messages to the server asynchronously and receive responses through the event system.
79
80
```python { .api }
81
async def send(self, data):
82
"""
83
Send a message to the server (coroutine).
84
85
Args:
86
data (any): Message data to send (will be JSON-serialized)
87
88
Raises:
89
SocketIsClosedError: If not connected to server
90
"""
91
```
92
93
### Event Handling
94
95
Register event handlers that can be either synchronous or asynchronous functions.
96
97
```python { .api }
98
def on(self, event, handler=None):
99
"""
100
Register an event handler (synchronous method).
101
102
Args:
103
event (str): Event name ('connect', 'message', 'disconnect')
104
handler (callable, optional): Event handler function (sync or async)
105
106
Returns:
107
callable: Decorator function if handler not provided
108
"""
109
```
110
111
Usage examples:
112
113
```python
114
# Async event handlers
115
@client.on('connect')
116
async def on_connect():
117
print('Connected to server')
118
await client.send('Hello Server!')
119
120
@client.on('message')
121
async def on_message(data):
122
print(f'Received from server: {data}')
123
# Can perform async operations in handlers
124
await asyncio.sleep(0.1)
125
await client.send(f'Echo: {data}')
126
127
@client.on('disconnect')
128
async def on_disconnect():
129
print('Disconnected from server')
130
131
# Synchronous handlers also work
132
@client.on('connect')
133
def on_connect_sync():
134
print('Connected (sync handler)')
135
```
136
137
### Async Background Tasks
138
139
Manage background tasks using asyncio.
140
141
```python { .api }
142
def start_background_task(self, target, *args, **kwargs):
143
"""
144
Start a background task using asyncio.
145
146
Args:
147
target (callable): Async task function to run
148
*args: Arguments for the task function
149
**kwargs: Keyword arguments for the task function
150
151
Returns:
152
asyncio.Task: Asyncio task object
153
"""
154
155
async def sleep(self, seconds=0):
156
"""
157
Sleep using asyncio (coroutine).
158
159
Args:
160
seconds (float): Sleep duration in seconds
161
"""
162
```
163
164
### Synchronous Utility Methods
165
166
Inherited synchronous methods from the base client class.
167
168
```python { .api }
169
def transport(self):
170
"""
171
Return the current transport name.
172
173
Returns:
174
str: Transport name ('polling' or 'websocket')
175
176
Raises:
177
ValueError: If not connected
178
"""
179
180
def create_queue(self, *args, **kwargs):
181
"""
182
Create an asyncio queue object.
183
184
Returns:
185
asyncio.Queue: Asyncio queue object
186
"""
187
188
def get_queue_empty_exception(self):
189
"""
190
Return the asyncio queue empty exception.
191
192
Returns:
193
asyncio.QueueEmpty: Asyncio queue empty exception
194
"""
195
196
def create_event(self, *args, **kwargs):
197
"""
198
Create an asyncio event object.
199
200
Returns:
201
asyncio.Event: Asyncio event object
202
"""
203
```
204
205
### AsyncClient-specific Methods
206
207
Methods specific to the async client implementation.
208
209
```python { .api }
210
def is_asyncio_based(self):
211
"""
212
Return True to identify as asyncio-based client.
213
214
Returns:
215
bool: Always True for AsyncClient
216
"""
217
```
218
219
## Client Lifecycle Events
220
221
The async client supports the same events as the synchronous client, but handlers can be async:
222
223
- **connect**: Fired when connection to server is established
224
- Handler signature: `async () -> None` or `() -> None`
225
226
- **message**: Fired when a message is received from the server
227
- Handler signature: `async (data: any) -> None` or `(data: any) -> None`
228
229
- **disconnect**: Fired when disconnected from the server
230
- Handler signature: `async () -> None` or `() -> None`
231
232
## Connection Examples
233
234
### Basic Async Connection
235
236
```python
237
import asyncio
238
import engineio
239
240
async def main():
241
client = engineio.AsyncClient()
242
243
@client.on('connect')
244
async def on_connect():
245
print('Connected!')
246
await client.send('Hello from async client')
247
248
@client.on('message')
249
async def on_message(data):
250
print(f'Server says: {data}')
251
252
@client.on('disconnect')
253
async def on_disconnect():
254
print('Disconnected')
255
256
await client.connect('http://localhost:5000')
257
await client.wait()
258
259
# Run the async main function
260
asyncio.run(main())
261
```
262
263
### Connection with Custom aiohttp Session
264
265
```python
266
import asyncio
267
import aiohttp
268
import engineio
269
270
async def main():
271
# Create custom aiohttp session
272
async with aiohttp.ClientSession() as session:
273
client = engineio.AsyncClient(
274
http_session=session,
275
request_timeout=10
276
)
277
278
await client.connect('http://localhost:5000')
279
await client.wait()
280
281
asyncio.run(main())
282
```
283
284
### Async Background Tasks
285
286
```python
287
import asyncio
288
import engineio
289
290
async def heartbeat_task(client):
291
"""Send periodic heartbeat messages"""
292
while True:
293
try:
294
await client.send({'type': 'heartbeat', 'timestamp': time.time()})
295
await asyncio.sleep(30)
296
except Exception as e:
297
print(f'Heartbeat failed: {e}')
298
break
299
300
async def main():
301
client = engineio.AsyncClient()
302
303
@client.on('connect')
304
async def on_connect():
305
print('Connected, starting heartbeat')
306
# Start background heartbeat task
307
client.start_background_task(heartbeat_task, client)
308
309
await client.connect('http://localhost:5000')
310
await client.wait()
311
312
asyncio.run(main())
313
```
314
315
### Automatic Reconnection with Async/Await
316
317
```python
318
import asyncio
319
import engineio
320
321
async def connect_with_retry(client, url, max_retries=5):
322
"""Connect with automatic retry logic"""
323
for attempt in range(max_retries):
324
try:
325
await client.connect(url)
326
print('Connected successfully')
327
return
328
except Exception as e:
329
print(f'Connection attempt {attempt + 1} failed: {e}')
330
if attempt < max_retries - 1:
331
await asyncio.sleep(2 ** attempt) # Exponential backoff
332
raise ConnectionError('Max connection attempts exceeded')
333
334
async def main():
335
client = engineio.AsyncClient()
336
337
@client.on('connect')
338
async def on_connect():
339
print('Connected to server')
340
341
@client.on('disconnect')
342
async def on_disconnect():
343
print('Disconnected, attempting to reconnect...')
344
await asyncio.sleep(5)
345
try:
346
await connect_with_retry(client, 'http://localhost:5000')
347
except Exception as e:
348
print(f'Reconnection failed permanently: {e}')
349
350
await connect_with_retry(client, 'http://localhost:5000')
351
await client.wait()
352
353
asyncio.run(main())
354
```
355
356
### Integration with Web Frameworks
357
358
```python
359
# FastAPI integration example
360
from fastapi import FastAPI
361
import engineio
362
363
app = FastAPI()
364
client = engineio.AsyncClient()
365
366
@app.on_event("startup")
367
async def startup():
368
await client.connect('http://external-service:5000')
369
370
@app.on_event("shutdown")
371
async def shutdown():
372
await client.disconnect()
373
374
@app.post("/send-message")
375
async def send_message(message: str):
376
await client.send(message)
377
return {"status": "sent"}
378
```
379
380
### Multiple Concurrent Connections
381
382
```python
383
import asyncio
384
import engineio
385
386
async def handle_client(client_id, url):
387
"""Handle a single client connection"""
388
client = engineio.AsyncClient()
389
390
@client.on('connect')
391
async def on_connect():
392
print(f'Client {client_id} connected')
393
394
@client.on('message')
395
async def on_message(data):
396
print(f'Client {client_id} received: {data}')
397
398
await client.connect(url)
399
await client.wait()
400
401
async def main():
402
# Connect multiple clients concurrently
403
tasks = [
404
handle_client(i, 'http://localhost:5000')
405
for i in range(5)
406
]
407
408
await asyncio.gather(*tasks)
409
410
asyncio.run(main())
411
```
412
413
## Error Handling
414
415
The async client may raise the same exceptions as the synchronous client:
416
417
- `ConnectionError`: When connection to server fails or is lost
418
- `SocketIsClosedError`: When attempting to send while not connected
419
- `ValueError`: When invalid parameters are provided
420
- `asyncio.TimeoutError`: When requests exceed the configured timeout
421
422
## Advanced Async Patterns
423
424
### Context Manager Usage
425
426
```python
427
import asyncio
428
import engineio
429
430
class AsyncEngineIOClient:
431
def __init__(self, url, **kwargs):
432
self.url = url
433
self.client = engineio.AsyncClient(**kwargs)
434
435
async def __aenter__(self):
436
await self.client.connect(self.url)
437
return self.client
438
439
async def __aexit__(self, exc_type, exc_val, exc_tb):
440
await self.client.disconnect()
441
442
# Usage
443
async def main():
444
async with AsyncEngineIOClient('http://localhost:5000') as client:
445
@client.on('message')
446
async def on_message(data):
447
print(f'Received: {data}')
448
449
await client.send('Hello')
450
await asyncio.sleep(10)
451
452
asyncio.run(main())
453
```