2

While looking over the new features in Python 3.x, I was intrigued by the asyncio library being added. After looking at the reference documentation, I decided to play around with it a little bit.

This worked well until I tried to make it work for multiple clients, and keep a list of all active/connected clients. This introduced a cyclic dependency between the server class and the session class.

Now, I've tried a few different ways to resolve this; however, there doesn't appear to be any way for me to get at this data directly from the server class through any method/functional call.

While I have been able to workaround this by using a "lazy" import, it seems like this my be indicative of either a poor design, a lack of understanding of the library itself, or a combination of both.

Code wise, I have a small sample put together. Am I missing an obvious solution here, or does my organization need to change to better support the functionality provided by the asyncio library?

__main__.py:

from network.server import Server

def main(args=None):
    s = Server()

    try:
        s.run()
    except KeyboardInterrupt:
        pass

    s.close()

if __name__ == "__main__":
    main()

server.py:

import asyncio

from network.session import Session

class Server:

    sessionList = []

    def __init__(self):    
        self.handler = None

        self.loop = asyncio.get_event_loop()

        self.coro = self.loop.create_server(Session, 'localhost', 1234)

    def run(self):
        self.handler = self.loop.run_until_complete(self.coro)

        print('Server Running On: {}'.format(self.handler.sockets[0].getsockname()))

        self.loop.run_forever()

    def close(self):
        self.handler.close()

        self.loop.run_until_complete(self.handler.wait_closed())

        self.loop.close()

    @staticmethod
    def add_session(session):
        Server.sessionList.append(session)

    @staticmethod
    def del_session(session):
        Server.sessionList.remove(session)

session.py:

import asyncio

class Session(asyncio.Protocol):

    def __init__(self):
        from network.server import Server

        self._transport = None

        Server.add_session(self)

    def connection_made(self, transport):
        self._transport = transport

        self._transport.write('Echo Server Example\r\n\r\n'.encode())

    def data_received(self, data):
        self._transport.write(data)

    def eof_received(self):
        self._transport.close()

    def connection_lost(self, exc):
        from network.server import Server

        Server.del_session(self)

        if exc is not None:
            self._transport.close()
1
  • Have a look at aiohttp for server / client handling. Commented Oct 26, 2015 at 9:14

1 Answer 1

2

You may pass server instance into Session constructor:

self.loop.create_server(lambda: Session(self), 'localhost', 1234)

Storing sessionList as global object is not the best practice.

I recommend saving it as self.sessionList = [] in Server.__init__ and converting both add_session and del_session from staticmethod into regular methods.

Sign up to request clarification or add additional context in comments.

1 Comment

It looks like your suggestion works as expected, so I have flagged the response as the accepted answer. One thing I did note from this: it prevents type hinting on the Server parameter in the Session constructor; however, I believe this is resolved with Python 3.5 via PEP 0484's forward declaration for hinting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.