首页 文章

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

提问于
浏览
0

我编写简单的udp客户端程序,但它无法正确接收数据报 .
我的代码如下 .

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

我写了asyncio文件中发布的UDP echo服务器协议程序 .
https://docs.python.org/3/library/asyncio-protocol.html#udp-echo-server-protocol

运行这些程序,我认为结果是这样的 .

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

但结果就是这样 .

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

结果为什么会改变?
我搜索有关asyncio模块,但我无法解决这个问题 .

1 回答

  • 0

    这是因为 while True 循环在下次发送呼叫之前不会将控制权交还给ioloop - input 正在阻止 . 只需添加一些异步睡眠,ioloop就可以处理接收数据的事件

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

    并且因为 input 也将在这里阻止,所以最好将它移动到单独的线程:

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

    我已将您的代码与waiting for user input in separate thread混合,当然要重构:)

相关问题