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