看卯与嘴上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)
片段的评论意见在各个地方的巧舌如簧源和其他地方提到,在Windows,sockets是把在非阻挡的模式在投票。结果回调 self.outgoing_cb
是不断呼吁,并写到插座失败这个错误信息:
[Errno 10035] A non-blocking socket operation could not be completed immediately
叫 sock.setblocking(True)
之前以书面似乎没有规避这一点。通过降低优先的投票,而忽略了错误信息,它的工作不如预期,但投迄今许多事件,并且消耗了大量的CPU。有没有办法绕过这个限制在窗口?
更新
我可以指出,即整个点的投票 POLLOUT
是,当你写信呼吁你不会得到 EAGAIN
/EWOULDBLOCK
.奇怪的错误消息,我的,我相信将Windows相当于2个错误代码。换句话说,我得到 gobject.IO_OUT
事件当插座不会让我写成功, 和 把它放到阻挡的模式仍然给了我这个不恰当的错误。
另一个更新
在Linux上,这种工作是否正确,这座是不切换到非阻挡的模式,我收到 IO_OUT
, 当插座让我写的没有阻止,或者投掷一个错误。这是这个功能我想最好模仿/恢复在窗。
进一步注意到
从 man poll
:
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 绑定正在使用 WSA事件选择 和 WaitForMultipleObjects()
模拟 poll()
, ,但结果是一样的......)
我不确定您想要的阻塞套接字方法如何工作。你不断地“醒来”,因为你要求在你可以写作的时候叫醒你。您只想指定当您有数据要写入时......但是,当它叫醒你时,系统不会真正告诉你 多少 您可以在不阻塞的情况下写入数据,因此这是使用非阻塞 I/O 的充分理由。
其他提示
吉奥 包含 GSocket, 一个"低级的网络插座的对象,"因为2.22.但是这尚未被移植到 pygobject on Windows.
我不知道如果这有助于(我不是精通该查询功能或MFC插座,不知道投票是你的程序结构的要求),所以借此与一粒盐:
但为了避免在写阻塞或EAGAIN,我们使用选择,即插槽添加到传递给选择写集合,如果选择()回来了RC = 0的插槽可写的时候了。 ..
我们在我们的应用程序使用的写循环是(在伪代码):
set_nonblocking.
count= 0.
do {
FDSET writefds;
add skt to writefds.
call select with writefds and a reaonsable timeout.
if (select fails with timeout) {
die with some error;
}
howmany= send(skt, buf+count, total-count).
if (howmany>0) {
count+= howmany.
}
} while (howmany>0 && count<total);