简体   繁体   English

无法在python3 asyncio中正确接收数据报

[英]cannot receive datagram correctly in python3 asyncio

I write simple udp client program, but it cannot receive datagram correctly. 我编写了简单的udp客户端程序,但无法正确接收数据报。
My code is below. 我的代码如下。

import asyncio

class EchoClientProtocol:
    def __init__(self, message, loop):
        self.message = message
        self.loop = loop
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport
        print('Send:', self.message)
        self.transport.sendto(self.message.encode())

    def datagram_received(self, data, addr):
        print('Received:', data.decode())

async def sendChar(transport, msg):
    print('send: ', msg)
    transport.sendto(msg.encode())

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    message = 'Hello World!'
    connect = loop.create_datagram_endpoint(
            lambda: EchoClientProtocol(message, loop),
            remote_addr=('127.0.0.1', 9999)
            )
    transport, protocol = loop.run_until_complete(connect)
    while (True):
        try:
            ch = input()
        except KeyboardInterrupt:
            break
        loop.run_until_complete(sendChar(transport, ch))
    loop.run_forever()
    transport.close()
    loop.close()

And I write UDP echo server protocol program posted in asyncio document. 并且我写了asyncio文件中发布的UDP echo server协议程序。
( https://docs.python.org/3/library/asyncio-protocol.html#udp-echo-server-protocol ) https://docs.python.org/3/library/asyncio-protocol.html#udp-echo-server-protocol

Running these programs, I think result is like this. 运行这些程序,我认为结果是这样的。

Send: Hello World!
Received: Hello World!
1
send: 1
Received: 1
2
send: 2
Received: 2

But result is this. 但是结果是这个。

Send: Hello World!
1
send: 1
Received: Hello World!
2
send: 2
Received: 1

Why is result shifted? 为什么结果会转移?
I search about asyncio module, but I cannot solve this problem. 我搜索有关asyncio模块的信息,但无法解决此问题。

It is because while True loop does not give back control to ioloop until next send call - input is blocking. 这是因为while True循环在下一次发送调用之前不会将控制权交还给ioloop- input处于阻塞状态。 Simply add some async sleep, so ioloop could handle events to receive data 只需添加一些异步睡眠,以便ioloop可以处理事件以接收数据

while (True):
    try:
        loop.run_until_complete(asyncio.sleep(0.001))
        ch = input()
    except KeyboardInterrupt:
        break
    loop.run_until_complete(sendChar(transport, ch))

And since input will block here as well, afaik it is the best to move it to separate thread: 由于input也会在此处阻塞,因此afaik最好将其移至单独的线程:

import threading
import asyncio

class EchoClientProtocol:
    def __init__(self, message, loop):
        self.message = message
        self.loop = loop
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport
        print('Send:', self.message)
        self.transport.sendto(self.message.encode())

    def datagram_received(self, data, addr):
        print('Received:', data.decode())

    def error_received(self, data, addr=None):
        raise data

async def sendChar(transport, msg):
    print('send: ', msg)
    transport.sendto(msg.encode())

user_input = [None]

# spawn a new thread to wait for input 
def get_user_input(user_input_ref):
    while True:
        user_input_ref[0] = input()

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    message = 'Hello World!'
    connect = loop.create_datagram_endpoint(
            lambda: EchoClientProtocol(message, loop),
            remote_addr=('127.0.0.1', 9999)
            )
    transport, protocol = loop.run_until_complete(connect)
    input_thread = threading.Thread(target=get_user_input, args=(user_input,))
    input_thread.daemon = True
    input_thread.start()
    while (True):
        if user_input[0] is not None:
            loop.run_until_complete(sendChar(transport, user_input[0]))
            user_input[0] = None
        loop.run_until_complete(asyncio.sleep(1))
    loop.run_forever()
    transport.close()
    loop.close()

I have mixed your code with waiting for user input in separate thread , of course to refactor :) 我将您的代码与等待用户输入的单独线程混合在一起,以便进行重构:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM