semore_1267
semore_1267

Reputation: 1447

Add asyncio functionality to TCP server?

I'm trying to add async functionality via the asyncio library, to a simple TCP server that I'm using. Here is my foobar example:

import os
import sys 
import socket 

class Server(object):
    def __init__(self, addr):
        self.ip, self.port = addr.split(":")
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)


    def listen(self):
        # Listen for incoming requests
        self.socket.bind((self.ip, int(self.port)))
        print("Listening")
        while True:
            try:
                stream, addr = self.socket.accept()
                self._handle_request(stream, addr)
            except socket.timeout:
                continue 

    def _handle_request(self, stream, addr):
        # Here I'm handling the request (read and send response)
        _mssg = self._recv_data(stream)
        pass 

    def _recv_data(self, stream):
        # unpacking the packed struct that was sent, reading 
        # 4-byte struct size first, then using stream.recv()
        # until the entire message has been read
        return 1


if __name__ == "__main__":
    srv = Server("127.0.0.1:9999")
    srv.listen()

I've read the Python docs example here regarding async, but I'm seeing that this example is using the built-in server functionality of the asyncio library. Could anyone help me generalize this to my simple TCP server? I need the flexibility of a custom solution (but still the functionality of the linked async server)

Upvotes: 2

Views: 752

Answers (1)

user4815162342
user4815162342

Reputation: 155436

If my understanding is correct, you are looking for guidance how to adapt existing TCP code to asyncio. You will definitely need to make substantial changes to the code, but the changes should be fairly straightforward.

For example, the code from the question could be adapted to asyncio as follows (untested):

import asyncio, struct

class Server(object):
    def __init__(self, addr):
        self.ip, self.port = addr.split(":")

    async def listen(self):
        # Listen for incoming requests
        asrv = await asyncio.start_server(self._handle_request, self.ip, int(self.port))
        print("Listening")
        # on Python 3.6 you would use something like
        # while True: await asyncio.sleep(1000)
        await asrv.serve_forever()

    async def _handle_request(self, reader, writer):
        addr = writer.get_extra_info('peername')
        # Here I'm handling the request (read and send response)
        print('handling', addr)
        msg = await self._recv_data(reader)
        # ...

    async def _recv_data(self, stream):
        size_msg = await stream.readexactly(4)
        size, = struct.unpack('l', size_msg)
        msg = await stream.readexactly(size)
        return msg

if __name__ == "__main__":
    srv = Server("127.0.0.1:9999")
    asyncio.get_event_loop().run_until_complete(srv.listen())

Upvotes: 2

Related Questions