将异步功能添加到TCP服务器吗?

时间:2018-12-07 01:38:09

标签: python-3.x python-asyncio

我正在尝试通过asyncio库将异步功能添加到我正在使用的简单TCP服务器上。这是我的foobar示例:

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()

我已经阅读了the Python docs example here的有关异步的内容,但是我看到该示例正在使用asyncio库的内置服务器功能。有人可以帮我将其推广到我的简单TCP服务器吗?我需要自定义解决方案的灵活性(但仍然需要链接的异步服务器的功能)

1 个答案:

答案 0 :(得分:2)

如果我的理解正确,那么您正在寻找有关如何使现有TCP代码适应asyncio的指南。您肯定需要对代码进行重大更改,但是更改应该非常简单。

例如,可以将问题中的代码修改为适用于asyncio,如下所示(未经测试):

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())