マニュアルページから:
SO_REUSEADDR プロトコルでサポートされている場合、bind() に提供されたアドレスの検証に使用される規則で、ローカル アドレスの再利用を許可する必要があることを指定します。このオプションは int 値を取ります。これはブール値のオプションです
いつ使用すればよいですか?「ローカルアドレスの再利用」が与えるのはなぜですか?
マニュアルページから:
SO_REUSEADDR プロトコルでサポートされている場合、bind() に提供されたアドレスの検証に使用される規則で、ローカル アドレスの再利用を許可する必要があることを指定します。このオプションは int 値を取ります。これはブール値のオプションです
いつ使用すればよいですか?「ローカルアドレスの再利用」が与えるのはなぜですか?
TCP の主な設計目標は、パケットの損失、パケットの並べ替え、および - ここで重要な - パケットの重複に直面しても、信頼できるデータ通信を可能にすることです。
接続が確立されている間、TCP/IP ネットワーク スタックがこれらすべてをどのように処理するかは明らかですが、接続が閉じた直後に発生するエッジ ケースがあります。会話の最後に送信されたパケットが複製されて遅延し、4 方向シャットダウンパケットが遅延パケットの前に受信者に到達した場合はどうなりますか? スタックは、その接続を忠実に閉じます。その後、遅延した重複パケットが表示されます。スタックは何をすべきか?
さらに重要なことは、特定の IP アドレスと TCP ポートの組み合わせで開いているソケットを持つプログラムがそのソケットを閉じ、その後しばらくして、プログラムがやってきて、同じ IP アドレスと TCP ポート番号でリッスンしたい場合、どうすればよいかということです。 ? (典型的なケース: プログラムが強制終了され、すぐに再起動されます。)
いくつかの選択肢があります。
これは、すべての一般的な TCP/IP スタックのデフォルトの動作です。2×MSL は通常 30 ~ 120 秒でnetstat
、期間として出力に表示されますTIME_WAIT
。その後、スタックは、TTLの期限切れが原因で不正なパケットが途中でドロップされたと想定し、ソケットが状態を離れて、その IP/ポートの組み合わせを再利用できるようにします。TIME_WAIT
SO_REUSEADDR
オプション via を設定して、この動作を要求する必要があります。setsockopt()
bind()
SO_REUSEADDR
一般的な使用パターンは、構成を変更し、変更を有効にするためにそのプログラムを再起動する必要があるためです。がないと、以前のインスタンスを強制終了したときに接続が開いていた場合、再起動されたプログラムの新しいインスタンスでSO_REUSEADDR
の呼び出しは失敗します。bind()
これらの接続は、TCP ポートTIME_WAIT
を 30 ~ 120 秒間保持するため、上記のケース 1 に該当します。
設定のリスクSO_REUSEADDR
は、あいまいさを生み出すことです。TCP パケットのヘッダーのメタデータは、スタックがパケットが古いかどうかを確実に判断できるほど十分に一意ではないため、新しいリスナーのソケットに配信するのではなく、ドロップする必要があります。明らかに今は死んでいるリスナーを対象としていました。
それが真実であることがわからない場合は、リッスンしているマシンの TCP/IP スタックが接続ごとに動作してその決定を下す必要があります。
ローカル IP:接続ごとに一意ではありません。実際、ここでの問題定義では、意図的にローカル IP を再利用していると述べています。
ローカル TCP ポート:同上。
リモート IP:あいまいさの原因となっているマシンが再接続する可能性があるため、パケットの適切な宛先を明確にすることはできません。
リモート ポート:正常なネットワーク スタックでは、発信接続のリモート ポートはすぐに再利用されませんが、16 ビットしかないため、スタックが数万を通過するように強制するのに 30 ~ 120 秒かかります。ポートを再利用します。コンピューターは、1960 年代にさかのぼって、それほど速く仕事をすることができました。
それに対するあなたの答えが、リモートスタックが一時的なTCPポートTIME_WAIT
の再利用を禁止するためにその側で何かをする必要があるということである場合、そのソリューションはリモートホストが無害であると想定しています。悪意のあるアクターは、そのリモート ポートを自由に再利用できます。
リスナーのスタックは、TCP 4 タプルのみからの接続を厳密に禁止することを選択できると思います。そのため、TIME_WAIT
状態の間、特定のリモート ホストが同じリモート一時ポートに再接続することはできませんが、TCP スタックを認識していません。その特定の洗練。
今日 TCP を再設計する場合、 TLSなどをオプションではない機能として統合すると思います。その効果の 1 つは、この種の不注意で悪意のある接続ハイジャックを不可能にすることですが、それには大きなフィールドを追加する必要があります。 (128 ビット以上) これは、現在のバージョンの TCP ( RFC 793 )のドキュメントが公開された 1981 年にはまったく実用的ではありませんでした。
このような強化がなければ、再バインドを許可することによって作成されるあいまいさは、次のTIME_WAIT
いずれかを行うことができることを意味します。接続; または b) 新しいリスナーのソケットの新しいデータが古いリスナーのソケットに誤って割り当てられ、誤って削除された。
安全なことは、TIME_WAIT
期間が終了するのを待つことです。
最終的には、コストの選択に帰着します。TIME_WAIT
期間を待つか、不要なデータ損失や不注意によるデータ注入のリスクを負うかです。
多くのサーバー プログラムは、このリスクを冒して、必要以上の着信接続を見逃さないように、サーバーをすぐにバックアップする方がよいと判断します。
これは普遍的な選択ではありません。多くのプログラム (設定の変更を適用するために再起動が必要なサーバー プログラムでさえ) は、そのままにしておくことを選択しますSO_REUSEADDR
。プログラマーはこれらのリスクを知っていて、デフォルトをそのままにしておくことを選択している場合もあれば、問題を認識していなくても賢明なデフォルトの恩恵を受けている場合もあります。
一部のネットワーク プログラムでは、エンド ユーザーまたはシステム管理者に責任を押し付けて、構成オプションの中からユーザーに選択肢を提供します。
SO_REUSEADDRを使用すると、サーバーを
TIME_WAIT状態のアドレスにバインドできます。
このソケットオプションは、このポートがビジー状態(TIME_WAIT状態)であっても、先に進んでそれを再利用することをカーネルに通知します。ビジーであるが別の状態の場合でも、すでに使用中のアドレスエラーが発生します。サーバーがシャットダウンされ、ソケットがポートでアクティブな状態ですぐに再起動された場合に便利です。
ソケットを作成するとき、実際にはそれを所有していません。OS(TCPスタック)がそれを作成し、それにアクセスするためのハンドル(ファイル記述子)を提供します。ソケットが閉じている場合、OSがいくつかの状態を経る間、OSが「完全に閉じる」には時間がかかります。EJPがコメントで述べたように、最も長い遅延は通常TIME_WAIT状態からです。この追加の遅延は、終了シーケンスの最後でエッジケースを処理し、最後の終了確認応答が通過したか、タイムアウトのために反対側が自動的にリセットされたことを確認するために必要です。ここでは、この状態に関するいくつかの追加の考慮事項を見つけることができます。主な考慮事項は次のように指摘されています:
TCPは、可能な限り、送信されるすべてのデータが配信されることを保証することを忘れないでください。ソケットを閉じると、サーバーはTIME_WAIT状態になります。これは、すべてのデータが通過したことを本当に確認するためです。ソケットが閉じられると、双方は互いにメッセージを送信することで、これ以上データを送信しないことに同意します。これは、私には十分に良さそうだったので、ハンドシェイクが完了したら、ソケットを閉じる必要があります。問題は2つあります。まず、最後のackが正常に通信されたことを確認する方法はありません。第二に、ネット上に「さまよう重複」が残っている可能性があり、それらが配信された場合に対処する必要があります。
同じip:portペアを使用して複数のソケットをすばやく作成しようとすると、以前のソケットが完全に解放されていないため、「アドレスはすでに使用されています」というエラーが発生します。SO_REUSEADDRを使用すると、以前のインスタンスのチェックが上書きされるため、このエラーが解消されます。