无法在 python3 asyncio 中正确接收数据报
cannot receive datagram correctly in python3 asyncio
我写了简单的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()
还有我写的UDP echo server协议程序贴在asyncio文档里
(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 模块,但我无法解决这个问题。
这是因为 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 混合在一起,当然是为了重构:)
我写了简单的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()
还有我写的UDP echo server协议程序贴在asyncio文档里
(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 模块,但我无法解决这个问题。
这是因为 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 混合在一起,当然是为了重构:)