python - 在 Windows 上使用 Glib 观察套接字将它们置于非阻塞模式

标签 python windows pygtk glib gio

以下代码在 Windows 上无法正常工作(但在 Linux 上可以):

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setblocking(True)
    sock.connect(address)
    gobject.io_add_watch(
            sock.fileno(),
            gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP,
            callback)

glib 源代码中不同地方的注释片段,以及其他地方提到在 Windows 中,套接字在轮询期间处于非阻塞模式。结果,不断调用回调 self.outgoing_cb,写入套接字失败并显示以下错误消息:

[Errno 10035] A non-blocking socket operation could not be completed immediately

在写入之前调用 sock.setblocking(True) 似乎并不能规避这一点。通过降低轮询的优先级并忽略错误消息,它按预期工作,但会抛出很多事件,并消耗大量 CPU。在 Windows 中有解决此限制的方法吗?

更新

我可能会指出,POLLOUT 轮询的全部意义在于,当您进行写调用时,您不会得到 EAGAIN/EWOULDBLOCK。我收到的奇怪错误消息,我相信这两个错误代码在 Windows 中是等效的。换句话说,当套接字不允许我成功写入时,我收到 gobject.IO_OUT 事件,并且将其置于阻塞模式仍然给我这个不适当的错误。

另一个更新

在 Linux 上,这可以正常工作,套接字没有切换到非阻塞模式,我收到 IO_OUT,此时套接字将让我在不阻塞或抛出错误的情况下写入。这是我想在 Windows 下最好地模拟/恢复的功能。

进一步说明

来自人工投票:

   poll()  performs a similar task to select(2): it waits for one of a set
   of file descriptors to become ready to perform I/O.
          POLLOUT
                 Writing now will not block.

来自 man select:

A file descriptor  is considered ready if it is possible to perform the corre‐
sponding I/O operation (e.g., read(2)) without blocking.

最佳答案

做非阻塞I/O有问题吗?如果您正在使用阻塞 I/O,那么使用轮询循环似乎有点奇怪。

当我编写这样的程序时,我倾向于执行以下操作:

  • 缓冲我要发送到文件描述符的字节。

  • 仅在所述缓冲区非空时才请求 IO_OUT(或 poll() 等价物,POLLOUT)事件。

  • poll()(或等价物)发出您已准备好写入的信号时,发出写入。如果您得到 EAGAIN/EWOULDBLOCK,请从缓冲区中删除您成功写入的字节并等待下次收到信号。如果您成功写入了整个缓冲区,则停止请求 POLLOUT,这样您就不会虚假地醒来。

(我的猜测是 Win32 绑定(bind)正在使用 WSAEventSelectWaitForMultipleObjects() 来模拟 poll(),但结果是一样的...)

我不确定您想要的阻塞套接字方法如何工作。你不断地“醒来”,因为你要求在你可以写作的时候叫醒你。您只想指定当您有数据要写入时...但是,当它唤醒您时,系统不会真正告诉您多少您可以在不阻塞的情况下写入数据,所以这就是这是使用非阻塞 I/O 的一个很好的理由。

关于python - 在 Windows 上使用 Glib 观察套接字将它们置于非阻塞模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1648631/

相关文章:

Python设置小数精度

python - 如何将关键字参数传递给 concurrent.futures 映射调用调用的函数

python - Python 中打印意外的换行符

python - 用于客户端 python 接口(interface)/raw_input 的 Twisted Reactor

windows - Go 无法在 DLL 中查找过程

c# - 使用 BinaryReader 读取大文件(>1 GB)时,最佳缓冲区大小是多少?

windows - 在 Windows C/C++ 中检查文件夹/文件是否被隐藏/系统

python - PyGTK 自定义信号发送一个列表作为参数

python - 使用 PyGTK 进行线程化

python - destroy() 后 FileChooserDialog 卡在屏幕上