在Windows上使用Glib观察套接字将使其处于非阻塞模式

以下代码在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的投票POLLOUT在于,当您进行写入调用时,您将不会收到EAGAIN / EWOULDBLOCK 。 我得到的奇怪的错误信息,我相信会是那些2错误代码的Windows等价物。 换句话说,我得到的gobject.IO_OUT事件时,套接字不会让我写成功,并将其置于阻塞模式仍然给我这个不恰当的错误。

另一个更新

在Linux上,这个工作正常,套接字不会切换到非阻塞模式,并且当套接字允许我写入没有阻塞或抛出错误时,我会收到IO_OUT 。 这是我想在Windows下最好的模拟/恢复function。

进一步说明

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 (eg, read(2)) without blocking. 

    执行非阻塞I / O是否有问题? 如果使用阻塞I / O,使用轮询循环似乎有点奇怪。

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

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

    • 当所述缓冲区非空时只请求IO_OUT (或poll()当量, POLLOUT )事件。

    • poll() (或等价的)已经表明你已经准备好写入时,发出写入。 如果你得到EAGAIN / EWOULDBLOCK ,从缓冲区中删除成功写入的字节,并等待下一次发送信号。 如果您成功编写了整个缓冲区,那么请停止向POLLOUT请求,以免虚假地唤醒。

    (我的猜测是,Win32绑定正在使用WSAEventSelect和WaitForMultipleObjects()来模拟poll() ,但结果是一样的…)

    我不知道你想要的阻塞套接字如何工作。 你一直在“醒来”,因为你在写作的时候要求把你叫醒。 你只想指定,当你有数据要写…但是,当它唤醒你时,系统不会真正告诉你有多少数据,你可以写没有阻塞,所以这是一个很好的理由,阻止I / O。

    GIO自2.22起包含GSocket ,一个“低级网络套接字对象”。 然而,这还没有被移植到Windows上的pygobject 。

    我不确定这是否有帮助(我不熟悉轮询功能或MFC套接字,不知道轮询是您的程序结构的要求),所以采取这一点盐:

    但是为了避免写入时发生阻塞或EAGAIN,我们使用select,即将套接字添加到传递给select的写集,如果select()返回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); 

    你可以使用Twisted ,它包括对GTK的支持 (甚至在Windows上),并且将处理Windows上非阻塞套接字想要引发的各种错误情况。