python-socketio: multiple namespace, race condition in asyncio, no individual sid

Problem

  1. sio.connect() first connects to namespace / before connecting to other namespaces. Subsequent emit() commands are allowed before all namespaces are connected to - causing messages to disappear (due to namespace not connected yet). Adding asyncio.sleep(1) before the first emit() seems to fix the problem,

  2. in the documentation https://python-socketio.readthedocs.io/en/latest/server.html#namespaces, 2nd paragraph suggests that

Each namespace is handled independently from the others, with separate session IDs (sids), …

it seems in my snippet below the same sid is used for all namespaces

am I missing something?

Code

Client code:

  
import time
import asyncio
import socketio
import logging

logging.basicConfig(level='DEBUG')
loop = asyncio.get_event_loop()
sio = socketio.AsyncClient()

@sio.event
async def message(data):
    print(data)

@sio.event(namespace='/abc')
def message(data):
    print('/abc', data)

@sio.event
async def connect():
    print('connection established', time.time())

@sio.event(namespace='/abc')
async def connect():
    print("I'm connected to the /abc namespace!", time.time())

async def start_client():
    await sio.connect('http://localhost:8080', transports=['websocket'],
                      namespaces=['/', '/abc'])
    # await asyncio.sleep(2)
    await sio.emit('echo', '12345')
    await sio.emit('echo', '12345', namespace='/abc')
    await sio.wait()

if __name__ == '__main__':
    loop.run_until_complete(start_client())

server code:

import socketio
import time
from aiohttp import web

sio = socketio.AsyncServer(async_mode = 'aiohttp')

app = web.Application()
sio.attach(app)

redis = None

@sio.event
async def connect(sid, environ):
    print("connected", sid, time.time())

@sio.event(namespace='/abc')
async def connect(sid, environ):
    print("connected /abc", sid, time.time())

@sio.event(namespace='/abc')
async def echo(sid, msg):
    print('abc', sid, msg)
    await sio.emit('message', msg, to=sid, namespace='/abc')
    
@sio.event
async def echo(sid, msg):
    print(sid, msg)
    await sio.emit('message', msg, to=sid)

if __name__ == '__main__':
    web.run_app(app)

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (8 by maintainers)

Most upvoted comments

For anyone reading this issue, and to avoid any confusion regarding statements made here that are out of date, let me summarize the current state of things:

  • Current versions of the Socket.IO protocol and this package use different sid values for each namespace a client is connected to. It is only older versions that used the same sid for all namespaces.
  • Namespaces are designed to each carry an independent connection from a logical point of view. In terms of implementation, all these namespaces are multiplexed over a single Engine.IO connection.
  • The client’s connect() method in current versions of this package waits for all requested namespaces to be connected before returning.

Given than what most of what is discussed here relates to old versions, I’m going to close this issue.