0

It's being a hard crash course for me in the last few weeks learning asyncio Stream library to build a server.

After solving a lot of small issues, I found one that simply doesn't make any sense. I am trying to start a bunch of servers (using loop.create_server) but for some reason, all servers work as the last spawned server. I even wrote a small program to show what I am talking about:

import asyncio


LST_SERVERS = [{'name': 'Server1', 'port': 10051},
               {'name': 'Server2', 'port': 10052},
               {'name': 'Server3', 'port': 10053}]

async def print_test():
    print('test')

class Protocol1(asyncio.Protocol):

    def __init__(self, name):
        print('starting')
        self.name = name

    def connection_made(self, transport):
        self.transport = transport
        self.peername = transport.get_extra_info("peername")
        print(f'New Connection on Protocol1: {self.peername}')

    def data_received(self, data):
        print(f'Data received: {data.decode("utf-8")}')
        self.transport.write(f'Hi, I am {self.name}'.encode('utf-8'))

    def connection_lost(self, ex):
        print(f'Disconnected {self.peername}')
        
class Protocol2(asyncio.Protocol):

    def __init__(self, name):
        print('starting')
        self.name = name

    def connection_made(self, transport):
        self.transport = transport
        self.peername = transport.get_extra_info("peername")
        print(f'New Connection on Protocol2: {self.peername}')

    def data_received(self, data):
        print(f'Data received: {data.decode("utf-8")}')
        self.transport.write(f'Hi, I am {self.name}'.encode('utf-8'))

    def connection_lost(self, ex):
        print(f'Disconnected {self.peername}')


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.create_task(print_test())
    for server in LST_SERVERS:
        print(f'Starting {server["name"]} on port {server["port"]}')
        name = server["name"]
        if name == 'Server1':
            protocol = Protocol1
        else:
            protocol = Protocol2
        
        server = loop.run_until_complete(
            loop.create_server(protocol_factory=lambda: protocol(name),
                               host='0.0.0.0',
                               port=server['port']))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        print('Server stoped')
    finally:
        loop.close()

I have a list of servers to start. Each one with a different port and a different name. I also have 2 different protocols (that are pretty much equal). When I run it, the first server would use the first protocol and the rest would use the second protocol (because of the line 54 condition). But look what happens after I run it and test using netcat all ports (to make it easy to understand, I used arrows to point what was input and what was output):

nc localhost 10051
> Hi 10051
< Hi, I am Server3^C
nc localhost 10052
> Hi 10052
< Hi, I am Server3^C
nc localhost 10053
> Hi 10053
< Hi, I am Server3

All of them are Server3??? Why?

Also, this is the program output:

Starting Server1 on port 10051
test
Starting Server2 on port 10052
Starting Server3 on port 10053
starting
New Connection on Protocol2: ('127.0.0.1', 47922)
Data received: Hi 10051

Disconnected ('127.0.0.1', 47922)
starting
New Connection on Protocol2: ('127.0.0.1', 34088)
Data received: Hi 10052

Disconnected ('127.0.0.1', 34088)
starting
New Connection on Protocol2: ('127.0.0.1', 41868)
Data received: Hi 10053

WTF? They are all Protocol2! Am I missing something? Is there another way to start a bunch of servers? I used this post on a maillist as a reference for running my code

0 Answers0