Windows ソケット API プログラムを使用して TCP サーバーへデータをコピーすると、パフォーマンスの低下が発生します。

適用対象: Microsoft Windows Server 2003 Enterprise Edition (32-bit x86)Microsoft Windows Server 2003 Standard Edition (32-bit x86)Microsoft Windows Server 2003 Web Edition

現象


Windows ソケット API を使用するプログラムを実行すると、TCP サーバーへデータをコピーするとパフォーマンスが低下があります。

Microsoft ネットワーク モニターなどのネットワーク スニファーでネットワーク トレースを行うと、TCP サーバーは、最後に、遅延 ack タイマー (遅延 ACK タイマーとも呼ばれます) で、TCP データ ストリーム内の TCP セグメントに対して TCP ACK セグメントを送信します。デフォルトで、Windows オペレーティング システムでは、このタイマーの値は 200 ミリ秒 (ms) です。データの 64 キロバイト (KB) を送信するための一般的なデータ フローは次の次の手順に似ています。
Client->Server 1460 bytesClient->Server 1460 bytes
Server->Client ACK
Client->Server 1460 bytes
Client->Server 1460 bytes
Server->Client ACK
....
Client->Server 1460 bytes
Client->Server 1460 bytes
Server->Client ACK-PUSH
Client->Server 1296 bytes
-> delayed ACK 200 ms



原因


この問題は、Afd.sys では、Windows ソケット API のアーキテクチャの動作のために発生します。この問題は、次の条件すべてに該当する場合に発生します。

  • Windows ソケット プログラムは、非ブロッキング ソケットを使用します。
  • 単一の送信呼び出しまたはWSASend呼び出しは、下位のソケット送信バッファーを入力します。

    などのプログラムは、そのソケットの初期化ルーチンの中に 32 kb のソケット送信バッファーの既定を変更するのには、Windows ソケットsetsockopt関数を使用します。
    setsockopt( sock, SOL_SOCKET, 32768, (char *) &val, sizeof( int ) );
    以降では、プログラムでは、データを送信するとき、送信呼び出しまたはWSASend呼び出しを発行し、各送信で 64 KB のデータを送信します。
    send(socket, pWrBuffer, 65536, 0);
    このシナリオでは、毎回 64 KB のデータの送信を呼び出すプログラムの問題を返しますエラー コードSOCKET_ERROR下位の 32 KB のソケット バッファーが完全にいっぱいの場合。WSAGetLastError関数を呼び出して、プログラムは、ときのエラー コードを受信します。ほとんどのプログラムは、ソケットの状態を確認するのには、Windows ソケット機能の選択を使用します。このシナリオでは、 select関数は報告ソケットが書き込み可能なクライアントは、未解決の TCP ACK セグメントを受け取るまで。Windows 環境で既定では、この可能性がありますほどかかる 200 ミリ秒遅延 ack のアルゴリズムがあるためです。
  • リモート TCP サーバーは、クライアントは push ビットが設定された最後の TCP セグメントを送信する前に、すべての TCP セグメントを確認します。

回避策


この問題を回避するには、次の方法のいずれかを使用します。

方法 1: ブロッキング ソケットを使用します。

この問題は、ブロック不可のソケットでのみ発生します。ブロッキング ソケットを使用すると、afd.sys のソケット バッファーが異なるためこの問題は発生しません。ブロッキングおよび非ブロッキング ソケットのプログラミングの詳細については、Microsoft プラットフォーム SDK のマニュアルを参照してください。

方法 2: を指定するようにソケット送信バッファーのサイズはプログラムの送信バッファーのサイズよりも大きい

ソケットの送信バッファーを変更するには、現在のソケット送信バッファーのサイズ (SO_SNDBUF)、およびソケットを設定するのにはsetsockopt関数を使用して送信バッファーのサイズを決定するのには Windows ソケットgetsockopt関数を使用します。完了したら、SO_SNDBUF 値は 1 バイト以上で、プログラムの送信バッファーのサイズより大きいである必要があります。

送信呼び出しを変更またはWSASend呼び出しでバッファーを指定のサイズを 1 バイト以上で、SO_SNDBUF 値よりも小さい。Setsockoptの呼び出し、次の値を変更してこの資料の「原因」のセクションで前述例を、
setsockopt( sock, SOL_SOCKET, 65537, (char *) &val, sizeof( int ) );
または送信するための呼び出し、次の値を変更する可能性があります。
send(socket, pWrBuffer, 32767, 0);
これらの値の任意の組み合わせを使用することもできます。

方法 3: TCP サーバー上の TCP/IP 設定を変更します。

重要 このセクション、方法、またはタスクには、レジストリの変更方法が記載されています。レジストリを誤って変更すると、深刻な問題が発生することがあります。そのため、レジストリを変更する際には十分に注意してください。万一に備えて、編集の前にレジストリをバックアップしてください。そうすることで、問題が発生した場合にレジストリを復元することができます。レジストリのバックアップ方法および復元方法の詳細を参照するには、以下のサポート技術情報番号をクリックしてください。
322756の方法をバックアップし、Windows のレジストリを復元するには


着信 TCP セグメントをただちに確認する TCP サーバー上の TCP/IP 設定を変更します。この回避策は、大規模なクライアントのインストール ベースを持つ、プログラムの動作を変更することはできません環境に最適です。リモート TCP サーバーが Windows ベースのサーバー上で実行されている場合、リモート サーバーのレジストリを変更する必要があります。その他のオペレーティング システムでは、遅延 ack タイマーを変更する方法の詳細についてはオペレーティング システムのマニュアルを参照してください。

Windows 2000 を実行しているサーバーでこれらの手順に従います。
  1. レジストリ エディター (Regedit.exe) を起動します。
  2. 次のレジストリ サブキーを見つけてクリックします。
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ < インターフェイス GUID >
  3. [編集] メニューで、値の追加] をクリックし、次のレジストリ値を作成します。

    値の名前:タイマー
    データ型: REG_DWORD
    値のデータ: 0
  4. レジストリ エディターを終了します。
  5. この変更を有効にする Windows を再起動します。
[Windows XP を実行しているサーバーまたは Windows Server 2003 では、これらの手順に従います。
  1. レジストリ エディターを起動します。
  2. 次のレジストリ サブキーを見つけてクリックします。
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ < インターフェイス GUID >
  3. [編集] メニューで、[新規] をポイントし、[DWORD 値] をクリックします。
  4. TcpAckFrequency、新しい値の名前を指定し、1 の値を割り当てます。
  5. レジストリ エディターを終了します。
  6. この変更を有効にする Windows を再起動します。

方法 4: ブロック不可のソケットの Afd.sys でバッファー動作を変更します。

重要 このセクション、方法、またはタスクには、レジストリの変更方法が記載されています。レジストリを誤って変更すると、深刻な問題が発生することがあります。そのため、レジストリを変更する際には十分に注意してください。万一に備えて、編集の前にレジストリをバックアップしてください。そうすることで、問題が発生した場合にレジストリを復元することができます。レジストリのバックアップ方法および復元方法の詳細を参照するには、以下のサポート技術情報番号をクリックしてください。
322756の方法をバックアップし、Windows のレジストリを復元するには


注: このレジストリ キーは、Windows Server 2003 Service Pack 1 およびそれ以降のサービス パックの利用可能なのみです。
  1. [スタート] ボタンregedit.exeと入力し、[ OK] をクリックします。
  2. 次のレジストリ サブキーを見つけてクリックします。
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
  3. [編集] メニューで、[新規] をポイントし、[DWORD 値] をクリックします。
  4. NonBlockingSendSpecialBuffering、新しい値の名前を指定し、1 の値を割り当てます。
  5. レジストリ エディターを終了します。
  6. この変更を有効にする Windows を再起動します。

状況


マイクロソフトは、この問題を「対象製品」セクションに記載されているマイクロソフト製品の問題として認識しています。

関連情報


Windows XP および Windows Server 2003 で TCP 受信確認 (ACK) の動作を制御する新しいレジストリ エントリを328890