首页 文章

假设socket.sendto是非阻塞操作是否安全?

提问于
浏览
3

我有一个用 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表示它执行系统调用,这使我担心它可能会阻塞整个循环 .

2 回答

  • -1

    不,你不能指望 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
    
  • 4

    sendto() 是非阻塞的,如果writer当前不可用,则可能会引发( BlockingIOErrorInterruptedError ) . socket.sendto()transport.sendto() 之间的区别在于 transport.sendto() 将首先尝试调用 socket.sendto() ,或者等到套接字准备好用 loop.add_writer() 写入,如果第一次尝试失败则再次调用 socket.sendto() .

    这是我从Python 3.5.2的asyncio模块的源代码中观察到的(Windows 32位)

    编辑:

    在Windows中,套接字操作阻止行为由 socket.settimeout 指定,因此请确保将超时值设置为 0 ,以便其操作不会阻止 .

相关问题