我想从Python 3.5.1中尝试新的asyncio
模块。这是我的测试代码:
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())
self.transport.close()
def datagram_received(self, data, addr):
print("Received:", data.decode())
print("Close the socket")
#self.transport.close()
def error_received(self, exc):
print('Error received:', exc)
def connection_lost(self, exc):
print("Socket closed, stop the event loop")
loop = asyncio.get_event_loop()
loop.stop()
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)
loop.run_forever()
transport.close()
loop.close()
当我运行时,翻译给了我:
Traceback (most recent call last):
File "C:\Users\oxygen\Documents\GitProjects\tests\python\udp\client.py", line
35, in <module>
loop.run_forever()
File "C:\Python35-32\lib\asyncio\base_events.py", line 295, in run_forever
self._run_once()
File "C:\Python35-32\lib\asyncio\base_events.py", line 1218, in _run_once
event_list = self._selector.select(timeout)
File "C:\Python35-32\lib\selectors.py", line 314, in select
r, w, _ = self._select(self._readers, self._writers, [], timeout)
File "C:\Python35-32\lib\selectors.py", line 305, in _select
r, w, x = select.select(r, w, w, timeout)
OSError: [WinError 10038] an operation was attempted on something that is not a socket
我认为这是由self.transport.sendto(self.message.encode())
和self.transport.close()
的序列引起的。如果我理解正确,sendto
方法是异步的,并且在我通过调用close
方法关闭套接字后实际调用它。有什么方法可以解决这个问题吗?
答案 0 :(得分:0)
DatagramTransport
(实际上_SelectorDatagramTransport
)计划连接上的两个操作,第一个是来自给定协议的connection_made
,第二个是_read_ready
(recvfrom) - 其中订单(https://github.com/python/asyncio/blob/master/asyncio/selector_events.py#L996)。
由于您在connection_made
上关闭了传输,因此以下操作(_read_ready
)失败。从那里删除self.transport.close()
。
您可能会发现有趣的asyncio udp examples。
答案 1 :(得分:0)
发送后解决 on_con_lost 未来:
import asyncio
class EchoClientProtocol:
def __init__(self, message, on_con_lost):
self.message = message
self.on_con_lost = on_con_lost
def connection_made(self, transport):
print("Send:", self.message)
self.transport = transport
self.transport.sendto(self.message.encode())
self.on_con_lost.set_result(True)
async def main() -> None:
loop = asyncio.get_running_loop()
transport, protocol = await loop.create_datagram_endpoint(
lambda: EchoClientProtocol(
"Hello World!",
on_con_lost=loop.create_future(),
),
remote_addr=("127.0.0.1", 9999),
)
try:
await asyncio.sleep(0.5)
await protocol.on_con_lost
finally:
transport.close()
if __name__ == "__main__":
asyncio.run(main())