我有一个用socket(AF_INET, SOCK_DGRAM)
创建的套接字对象,我将在asyncio循环中使用它。但是我无法在https://docs.python.org/3/library/asyncio-eventloop.html#low-level-socket-operations中找到sendto
函数。
我可以安全地假设此函数是一个非阻塞系统调用,可以在asyncio循环中调用吗?或者我应该将其提交到另一个使用run_in_executor
的线程中运行吗?
** Documentation表示它执行系统调用,这可能会阻止整个循环。
答案 0 :(得分:4)
不,您不能指望socket.sendto
是非阻止的。
相反,请使用DatagramTransport.sendto:
将数据字节发送到addr给出的远程对等体(传输 - 依赖于目标地址)。如果addr为None,则将数据发送到传输创建时给出的目标地址。
此方法不会阻止; 它会缓冲数据并安排将数据异步发送出去。
数据报传输由loop.create_datagram_endpoint协程返回:
transport, protocol = await loop.create_datagram_endpoint(factory, sock=sock)
编辑 - 关于您的评论:
socket.sendto()是否等同于transport.sendto()?
不,不是transport.sendto
使用loop.add_writer
来使操作无阻塞。请参阅implementation。
我不想使用这种方法,因为它的实现强制我通过回调样式的协议接收数据。
asyncio的较低级别基于回调,asyncio不为UDP提供基于协程的对象。但是,我写了module that provides high-level UDP endpoints for asyncio。
用法:
async def main():
local = await open_local_endpoint()
remote = await open_remote_endpoint(*local.address)
remote.write(b'Hey Hey, My My')
data, addr = await local.read()
message = "Got {data!r} from {addr[0]} port {addr[1]}"
print(message.format(data=data.decode(), addr=addr))
输出:
Got 'Hey Hey, My My' from 127.0.0.1 port 45551
答案 1 :(得分:-1)
sendto()
是非阻止的,如果编写器当前不可用,则可能会引发(BlockingIOError
,InterruptedError
)。 socket.sendto()
和transport.sendto()
之间的区别在于transport.sendto()
将首先尝试调用socket.sendto()
,或者等到套接字准备好用loop.add_writer()
写入并调用{{1}如果第一次尝试失败则再次发送。
这是我从Python 3.5.2(Windows 32位)的asyncio模块的源代码中观察到的
编辑:
在Windows中,套接字操作阻止行为由socket.sendto()
指定,因此请确保将超时值设置为socket.settimeout
,以便其操作不会阻止。