以下代码在 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)正在使用 WSAEventSelect 和 WaitForMultipleObjects()
来模拟 poll()
,但结果是一样的...)
我不确定您想要的阻塞套接字方法如何工作。你不断地“醒来”,因为你要求在你可以写作的时候叫醒你。您只想指定当您有数据要写入时...但是,当它唤醒您时,系统不会真正告诉您多少您可以在不阻塞的情况下写入数据,所以这就是这是使用非阻塞 I/O 的一个很好的理由。
关于python - 在 Windows 上使用 Glib 观察套接字将它们置于非阻塞模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1648631/