今日は、TCPで通信を行うWindows同士のクライアントサーバーシステムの、通信異常時挙動テストを行いました。で、サーバーのアプリケーションを終了した状態で、クライアントからサーバーに対して、接続要求を投げげると、タイムアウトするまでに21秒という何とも中途半端な時間がかかっていました。21秒って何やねんーというお話でございます。


TCPスタックは、SYNパケットを送信してから、サーバーからSYN, ACKが返ってくるまで、一定時間待ってみます。この一定時間がデフォルトで3秒です。そして、3秒ダメならリトライしてみます。この時、倍の時間待ってみます。つまり6秒ですね。そして、デフォルトのリトライ回数は2回となっています。6秒待ってダメなら、さらにリトライしてみます。この時、再び倍の時間待ってみます。つまり12秒です。それでダメなら諦めて、タイムアウトとする訳です。


この時間が3 + 6 + 12で、合計21秒になるのです。1回目のタイムアウト時間が3秒なのも、リトライ回数が2回なのもレジストリより、設定変更が可能です。

キー:HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParameters
初回のタイムアウト時間の値:InitialRtt (デフォルト3000[msec])
リトライ回数の値:TcpMaxConnectRetransmissions (デフォルト2[回])


つまり、タイムアウトの時間は以下の感じで求められるということですね。

初回:t秒待ってみる。
1回目のリトライ:(t * 2)秒待ってみる。
2回目のリトライ:(t * 4)秒待ってみる。
・・・
n回目のリトライ:(n * (2 ^ (t - 1)))秒待ってみる。


参考:TCP 初期再送タイマーの調整 Windows NT 4.0 に追加