【问题标题】:simple python asyncio server does not read data简单的python异步服务器不读取数据
【发布时间】:2018-02-18 21:13:37
【问题描述】:

我在 windows10 上使用 python3.6 和 asyncio 来制作一个简单的服务器。我无法让服务器按我想要的方式工作。 但是使用套接字接口实现的同一服务器按预期工作。 这是工作服务器

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind(('', 3201))
    s.listen(1)
    conn, addr = s.accept()
    with conn:
        print('Client connection: {}:{}'.format(*addr))
        while True:
            data = conn.recv(1024)
            if data:
                print('recv {} bytes'.format(len(data)))
            else:
                print('no data')
                break
print('connection closed')

我用 nc 命令测试它。例如

nc 10.68.100.32 3201
abc
ab
a
^C

服务器打印:

Client connection: 10.68.101.87:55243
recv 4 bytes
recv 3 bytes
recv 2 bytes
no data
connection closed    

但是我不能用 asyncio 做同一个服务器。 这是一个协议版本:

import asyncio

class ListenServer(asyncio.Protocol):

    def connection_made(self, transport):
        address = transport.get_extra_info('peername')
        print('connection made by client:{}:{}'.format(*address))

    def data_deceived(self, data):
        print('received {}'.format(len(data)), flush=True)

    def eof_received(self):
        print('print received EOF')

    def connection_lost(self, error):
        if error:
            print('ERROR: {}'.format(error))
        else:
            print('connection closed')

event_loop = asyncio.get_event_loop()
factory = event_loop.create_server(ListenServer, '', 3201)
server = event_loop.run_until_complete(factory)

event_loop.run_forever()
print('closing server')
server.close()

对于与上述服务器写入相同的 nc 测试序列:

connection made by client:10.68.101.87:55247
print received EOF
connection closed

服务器的异步协程 API 版本也失败了:

import asyncio

async def just_read(reader, writer):
    cli_host, cli_port = writer.get_extra_info('peername')
    print('Client connected {}:{}'.format(cli_host, cli_port))
    while True:
        data = await reader.read()
        if data:
            print('received {} bytes'.format(len(data)), flush=True)
        else:
            print('closing')
            writer.close()
            return

event_loop = asyncio.get_event_loop()
coro = asyncio.start_server(just_read, '', 3201, loop=event_loop)
server = event_loop.run_until_complete(coro)

event_loop.run_forever()
server.close()
print('Connection closed')

这种情况下的输出略有不同:

Client connected 10.68.101.87:55253
received 9 bytes
closing

在这种情况下,当我用 ^C 关闭 nc 时,我会得到所有数据, 并且服务器继续,所以我可以再次连接。

我希望服务器读取并打印出客户端写入的内容, 只要客户端连接,它就会连接一次并保持连接。 我如何使用 asyncio 来实现这一点,我应该使用协议版本还是协程版本,这有关系吗?

这只是我希望服务器执行的几项任务中的第一个,可能也是最简单的。 此处未显示的其他任务是开始定期发送虚拟消息 并针对不同的消息发送响应。

【问题讨论】:

  • 虽然这不是一个解决方案,而是一个建议,但我强烈建议将 Sanic 之类的框架用于异步服务器。往往更健壮
  • 请编辑问题以提供重现问题的最小示例。带走任何不是绝对必要的东西,例如struct.pack 等等。另外,请指定您如何测试服务器。您是与一位客户联系,还是与一位以上的客户联系?客户是否曾经断开连接?客户端是否读取服务器写入的消息?什么时候开始出现异常?
  • 我的意思是,将服务器简化为只编写简单的 ASCII 消息,并使用nc 连接到它。如果这工作正常,然后尝试确定小例子和真实例子之间的差异。如果它不起作用,则编辑问题以包括(仅)较小的服务器和重现问题的步骤。
  • @user4815162342,好建议!我正在开发一个更简单的版本,并将其作为新问题发布并从此处链接到它。
  • 这最终取决于你,但我建议简单地编辑这个问题。就目前而言,这几乎是无法回答的,因为我们无法重现您遇到的问题。另外,请尽量使示例尽可能短——确保删除所有注释掉的调用(例如当前问题中的my_server.send_periodic()writer.drain())或不必要的代码(KeyboardInterrupt 处理)。力求简洁和可重复。

标签: python-asyncio


【解决方案1】:

协议代码包含一个错字,它将方法命名为data_deceived 而不是data_received。更正方法名称后,输出与阻塞示例中的输出相同。

在协程版本中,问题在于reader.read() 指示asyncio 收集数据直到文件结束,并在准备好时提供。将其更改为reader.read(1024),类似于阻塞版本中的sock.recv(1024),可以修复代码。

【讨论】:

    猜你喜欢
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 2014-06-18
    • 1970-01-01
    • 2010-12-14
    • 2018-08-20
    相关资源
    最近更新 更多