2

Windows XPで、ノンブロッキング ソケットで繰り返しWSASendを呼び出すと、WSAENOBUFS で失敗します。

ここには2つのケースがあります:

ケース 1:

ノンブロッキング ソケットでは、WSASendを呼び出しています。擬似コードは次のとおりです。

while(1)
{
    result = WSASend(...); // Buffersize 1024 bytes
    if (result == -1)
    {
        if (WSAGetLastError() == WSAENOBUFS)
        {
            // Wait for some time before calling WSASend again
            Sleep(1000);
        }
    }
}

この場合、WSASend は約 88000 回正常に戻ります。次に、WSAENOBUFS で失敗し、コードに示されているように、しばらくしてから試行しても回復しません。

ケース 2:

この問題を解決するために、私はこれを参照し、そこで提案されているように、上記のコードの直前に、SO_SNDBUF を指定してsetsockoptを呼び出し、バッファーサイズを 0 (ゼロ) に設定しました。

この場合、WSASend は約 2600 回正常に戻ります。その後、失敗します。しかし、2600回待った後、再び成功し、失敗します。

今、私は両方のケースでこれらの質問をしています:

ケース 1:

  1. ここでこの88000という数字を決定する要因は何ですか?
  2. 失敗の原因が TCP バッファがいっぱいだった場合、しばらくして回復しなかったのはなぜですか?

ケース 2:

  1. 繰り返しますが、ここで 2600 という数字を決定する要因は何ですか?
  2. Microsoft KB 記事にあるように、内部 TCP バッファの代わりにアプリケーション バッファから直接送信すると、WSAENOBUFS で失敗するのはなぜですか?

編集:

非同期ソケット (Windows XP の場合) の場合、動作はさらに奇妙になります。WSAENOBUFS を無視してさらにソケットへの書き込みを続けると、最終的に WSAECONNRESET が切断されます。そして、なぜそれが起こるのか、現時点ではわかりませんか?

4

1 に答える 1

5

値は文書化されておらず、アプリケーションとネットワーク ドライバーの間にあるマシンにインストールされているものによって異なります。それらは、マシンのメモリ量に関連している可能性があります。制限 (ほとんどの場合、非ページ プール メモリと I/O ページ ロックの制限) は、Vista 以降でははるかに高い可能性があります。

この問題に対処する最善の方法は、アプリケーション レベルのフロー制御をプロトコルに追加して、好きな速度で送信できると想定しないようにすることです。ノンブロッキングおよび非同期 I/O によってリソースの使用量が急増する原因と、独自のフロー制御がない限りリソースを制御できない方法の詳細については、このブログ投稿を参照してください。

要約すると、非ブロッキング/非同期 API を使用して好きなだけ高速にデータをワイヤに書き込むことができると想定しないでください。TCP/IP の内部フロー制御がどのように機能するかにより、制御不能な量のローカル マシン リソースを使用する可能性があり、それらのリソースがサーバー上の O/S に解放される速度を制御できるのはクライアントだけであることに注意してください。機械。

于 2013-10-28T14:11:35.093 に答える