3

次のコードは、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です。私が受け取っている奇妙なエラー メッセージは、これら 2 つのエラー コードに相当する Windows のものだと思います。言い換えれば、gobject.IO_OUTソケットが正常に書き込みを許可しない場合にイベントを取得していますが、それをブロック モードにすると、この不適切なエラーが発生します

別のアップデート

これが正しく機能する Linux では、ソケットは非ブロッキング モードに切り替えられず、ソケットがIO_OUTブロックせずに、またはエラーをスローせずに書き込みを許可するときに を受け取ります。Windowsでエミュレート/復元したいのはこの機能です。

その他の注意事項

から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.
4

4 に答える 4

1

GIOには、2.22 以降の「低レベル ネットワーク ソケット オブジェクト」であるGSocketが含まれています。ただし、これはまだWindows の pygobject に移植されていません。

于 2010-10-31T08:46:25.843 に答える
0

Twistedを使用できます。これには、GTKのサポートが含まれており(Windowsでも)、Windowsの非ブロッキングソケットで発生する可能性のあるさまざまなエラー状態をすべて処理します。

于 2011-05-09T16:41:12.533 に答える
0

これが役立つかどうかはわかりません (私はポーリング機能や 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);
于 2009-11-19T13:43:35.007 に答える