オプションの正式な意味は理解できたと思います。現在処理しているいくつかのレガシーコードでは、オプションが使用されます。顧客は、RSTについて、その側からの接続に近い側からのFINへの応答として不満を持っています。
いつ使うべきかわからないので、安全に外せるかわかりません。
オプションが必要になる時期の例を教えていただけますか?
回答:
SO_LINGER
タイムアウトをゼロに設定する一般的な理由は、そのTIME_WAIT
状態にある多数の接続を回避し、サーバーで使用可能なすべてのリソースを占有することです。
TCP接続が完全に閉じられると、クローズを開始した側(「アクティブクローズ」)は、接続TIME_WAIT
が数分間留まることになります。したがって、サーバーが接続をクローズするプロトコルであり、有効期間が短い接続が非常に多数含まれている場合、この問題の影響を受ける可能性があります。
ただし、これは良い考えではありません- TIME_WAIT
理由のために存在します(古い接続からの浮遊パケットが新しい接続に干渉しないようにするため)。可能であれば、クライアントが接続を閉じる開始プロトコルにプロトコルを再設計することをお勧めします。
TIME_WAIT
して、クライアントは害を及ぼすことなく座ります。「UNIXネットワークプログラミング」の第3版(Stevens et al)の203ページにあるとおり、「TIME_WAIT状態はあなたの友人であり、私たちを助けるために存在します。この状態を回避しようとするのではなく、理解する必要があります(セクション2.7)。 」
私の提案として、最後のセクション「タイムアウト0でSO_LINGERを使用する場合」をお読みください。
その前に、以下について少し講義します。
TIME_WAIT
FIN
、ACK
およびRST
通常のTCP終了シーケンスは次のようになります(簡略化)。
AとBの2つのピアがあります。
close()
FIN
がBに送信するFIN_WAIT_1
状態になるFIN
ACK
がAに送信CLOSE_WAIT
状態になりますACK
FIN_WAIT_2
状態になるclose()
FIN
がAに送信LAST_ACK
状態になりますFIN
ACK
がBに送信するTIME_WAIT
状態になるACK
CLOSED
状態になります–つまり、ソケットテーブルから削除されますしたがって、終了を開始する(つまり、close()
最初にコールする)ピアは最終的にそのTIME_WAIT
状態になります。
TIME_WAIT
州が友だちである理由を理解するには、Stevensらによる「UNIXネットワークプログラミング」第3版(43ページ)のセクション2.7をお読みください。
しかし、それは多くのソケットで問題になる可能性があります TIME_WAIT
最終的には新しい接続が受け入れられなくなる可能性があるため、サーバー上の状態ます。
この問題を回避するために、を呼び出す前に、SO_LINGERソケットオプションをタイムアウト0に設定することをお勧めしますclose()
。ただし、これはTCP接続がエラーで終了する原因となるため、不適切なソリューションです。
代わりに、接続の終了が常にクライアント側から開始されるようにアプリケーションプロトコルを設計します。クライアントが残りのすべてのデータを読み取ったことを常に認識している場合は、終了シーケンスを開始できます。例として、ブラウザはContent-Length
HTTPヘッダーからすべてのデータを読み取り、クローズを開始できることを認識しています。(私は、HTTP 1.1では、可能な再利用のためにしばらく開いたままにし、その後閉じることを知っています。)
サーバーが接続を閉じる必要がある場合は、サーバーがクライアントに呼び出しを要求するようにアプリケーションプロトコルを設計します。 close()
。
この場合も、「UNIXネットワークプログラミング」の第3版のページ202-203によると、SO_LINGER
呼び出しの前にタイムアウト0を設定close()
すると、通常の終了シーケンスが開始されません。
代わりに、このオプションを設定して呼び出しをclose()
行うピアRST
は、エラー状態を示す(接続リセット)を送信します。これにより、相手側でこの状態が認識されます。通常、「ピアによる接続のリセット」などのエラーが表示されます。
そのため、通常の状況では、それはセットには本当に悪い考えですSO_LINGER
呼び出す前にタイムアウト0とclose()
今から呼び出さに- 失敗に終わっ近いです -サーバーアプリケーションで。
ただし、特定の状況では、とにかくそうすることが保証されます。
CLOSE_WAIT
、TIME_WAIT
状態に陥ったりするのを避けるために、中止を行うことは理にかなっています。TIME_WAIT
呼び出す場合)数千のサーバーソケットを回避するためにこのソケットオプションを設定することを検討してください。close()
再起動後。CLOSE_WAIT
、スタックしたターミナルにデータを配信しようとすると永久にハングする場合があります。ポートですがRST
、保留中のデータを破棄することができた場合、スタックポートを適切にリセットします。」私はあなたの質問に非常に良い答えを与えると私が信じているこの長い記事をお勧めします。
TIME_WAIT
:それが原因の問題に起動しない唯一の友人であるstackoverflow.com/questions/1803566/...
lingerがオンでタイムアウトがゼロの場合、TCPスタックは接続を閉じる前に保留中のデータが送信されるのを待ちません。これが原因でデータが失われる可能性がありますが、この方法で長引くように設定すると、これを受け入れ、接続を正常に閉じるのではなく、すぐにリセットするように要求します。これにより、通常のFINではなくRSTが送信されます。
EJPのコメントに感謝します。詳細については、こちらをご覧ください。
コード内の残留を安全に削除できるかどうかは、アプリケーションのタイプによって異なります。それは「クライアント」(TCP接続を開いてアクティブに最初に閉じる)か、「サーバー」(TCPのオープンと反対側がクローズを開始した後にそれを閉じる)?
アプリケーションに「クライアント」(最初に閉じる)のフレーバーがあり、さまざまなサーバーへの膨大な数の接続を開始およびクローズする場合(たとえば、アプリが膨大な数のさまざまなサーバーの到達可能性を監視する監視アプリである場合)すべてのクライアント接続がTIME_WAIT状態でスタックするという問題があります。次に、タイムアウトをデフォルトよりも小さい値に短くして、正常にシャットダウンし、クライアント接続リソースをより早く解放することをお勧めします。0はFINでは正常にシャットダウンせず、RSTでは異常終了するため、タイムアウトを0に設定しません。
アプリケーションに「クライアント」のフレーバーがあり、同じサーバーから大量の小さなファイルをフェッチする必要がある場合は、ファイルごとに新しいTCP接続を開始して、TIME_WAITで大量のクライアント接続になることはありませんが、接続を開いたままにし、同じ接続を介してすべてのデータをフェッチします。Lingerオプションは削除でき、削除する必要があります。
アプリケーションが「サーバー」(ピアのクローズへの反応として2番目に閉じる)の場合、close()で接続が正常にシャットダウンされ、TIME_WAIT状態に入らないためリソースが解放されます。リンガーは使用しないでください。しかし、サーバーアプリに監視プロセスがあり、アクティブでない開いている接続が長時間アイドル状態であることが検出されている場合(「長い」と定義されます)、この非アクティブな接続を側からシャットダウンできます。これは、残存タイムアウトを0に設定することによって行われます。close()は、RSTをクライアントに送信し、怒っていることを伝えます:-)
サーバーでは、誤動作しているクライアントを切断するときではRST
なく、送信したい場合がありFIN
ます。FIN-WAIT
これによりTIME-WAIT
、サーバーのソケット状態がスキップされます。これにより、サーバーリソースが使い果たされないようになり、このようなサービス拒否攻撃から保護されます。
DOS攻撃がサーバーリソースを使い果たす可能性があるというマキシムの観察が好きです。それはまた、実際に悪意のある敵なしで起こります。
一部のサーバーは、クライアントアプリに接続リークのバグがある場合に発生する「意図しないDOS攻撃」に対処する必要があり、サーバーに送信する新しいコマンドごとに新しい接続を作成し続けます。そして、GCのプレッシャーに達した場合、最終的には接続を閉じるか、接続がタイムアウトする可能性があります。
別のシナリオは、「すべてのクライアントが同じTCPアドレスを持っている」シナリオです。その場合、クライアント接続は、ポート番号によってのみ区別できます(単一のサーバーに接続する場合)。そして、クライアントが何らかの理由で接続の開閉を急速に循環し始めた場合、(クライアントアドレス+ポート、サーバーIP +ポート)タプルスペースを使い果たす可能性があります。
したがって、サーバーは、TIME_WAIT状態のソケットが多数ある場合、Linger-Zero戦略に切り替えることをお勧めします。クライアントの動作は修正されませんが、影響が軽減される可能性があります。
サーバー上の待機ソケットは、時間0のlingerを使用して、ソケットへのバインディングに即座にアクセスし、接続がまだ完了していないクライアントをリセットできます。TIME_WAITは、マルチパスネットワークがあり、パケットの順序が正しくない場合や、奇数のネットワークパケットの順序/到着タイミングを処理している場合にのみ興味深いものです。