pythonsocket.iopython-socketio

Python-socketio: How to connect one client to multiple servers?


There is plenty of information and examples when it comes to connecting to one server with multiple clients. But I was wondering is there a way for one client to connect to two servers at the same time? Here is my situation:

I have a python client that brings data from one server, analyzes it and sends an appropriate command to another server. There seems to be less information on this issue, If I may call it.

Here is how I tried approaching the issue. First, I made a socketio.Client class, which would enable me to create two client instances. It did not work. What am I missing here?:

import socketio

class SocketClient(socketio.Client):
    def __init__(self, server_ip):
        self.server_ip = server_ip    # server's ip address
        self.sio = socketio.Client(logger=True)

    def connect(self):
        self.sio.connect(self.server_ip, namespaces=['/my_namespace'])

    @self.sio.event
    def connect_error(self, error):
        print('connection error=> ', error)

    @self.sio.event
    def my_event(self, server_response):
        # Here I have to take the server_response 
        # and send it to another server.
        # How do I do it?
        # self.sio.emit('some_event', server_response)
        # that does not work, as I do not have the second client instance

        pass

    @self.sio.event
    def my_other_event(self, server_response):
        # process the response
        pass


# initiate the two client instances:
if __name__ == '__main__':
    first_client = SocketClient('http://192.168.100.103')
    second_client = SocketClient('http://192.168.100.104')
    first_client.connect()
    second_client.connect()

after my first try did not work, I ditched the class-instance approach and went for functional one:


import socketio

first_client = socketio.Client()
second_client = socketio.Client()


@second_client.event
@first_client.event
def connect():
    print(f'connected with id {first_client.sid}')

@second_client.event
@first_client.event
def connect_error(e):
    print('Error=> ', e)


@second_client.event
@first_client.event
def disconnect():
    print('disconnected')


@first_client.event
def my_event(server_response):
    # Here I have to take the server_response 
    # and send it to another server.
    second_client.emit('some_event', server_response)   # is it even possible?
    


@second_client.event
def my_other_event(server_response):
    # handle the response
    pass

if __name__ == '__main__':
    first_client.connect('http://192.168.100.103')
    second_client.connect('http://192.168.100.104')

In both cases, I am technically creating two clients. I might as well make them into separate files like first_client.py and second_client.py.

See where I am going with this? The goal is to get the data from server one, process it and send it to the other server with ideally one client. Please forgive me if I am missing something very obvious here. Any help is much appreciated.

P.S. both servers are up and running without any problem.


Solution

  • I am using NameSpace to solve this problem.

    first make a Namespace class

    class MyCustomNamespace(socketio.AsyncClientNamespace):
        async def on_connect(self):
            print("I'm connected!")
    
        async def on_disconnect(self):
            print("I'm disconnected!")
    
        async def on_my_event(self, data):
            await self.emit('my_response', data)
    
        async def on_message(self, data):
            print("[echo]:", data)
    
    class mysio:
        
        def __init__(self) -> None:
            global sio
            self.sio = socketio.AsyncClient(logger=False, engineio_logger=False)
            self.sio.register_namespace(MyCustomNamespace('/')) # bind
    
    

    then make 2 clients. since wait() will block the process, I use create_task().

    async def main():
    
        async def fun1():
            sio1 = mysio().sio
            await sio1.connect('http://192.168.3.85:11451')
            await sio1.emit('message', b'11111110001')
            await sio1.wait()
    
        async def fun2():
            sio2 = mysio().sio
            await sio2.connect('http://localhost:8080')
            await sio2.emit('message', 'from sio2')
            await sio2.wait()
    
        tasks = [asyncio.create_task(fun1()),asyncio.create_task(fun2()) ]
        await asyncio.wait(tasks)
    
    asyncio.run(main())