21

Linux環境下でのC言語でのソケットプログラミングでSO_KEEPALIVEオプションの使い方を学ぼうとしていました。

サーバーソケットを作成し、ブラウザを使用して接続しました。成功してGETリクエストは読めたのですが、SO_KEEPALIVEの使い方で行き詰まりました。

このリンクkeepalive_description@tldg.orgを確認しましたが、使用方法を示す例が見つかりませんでした。

accept()関数でクライアントの要求を検出するとすぐに、クライアント ソケットにSO_KEEPALIVEオプション値を設定します。1クライアントがダウンしているかどうかを確認する方法、送信されるプローブ間の時間間隔を変更する方法など、わかりません。

つまり、クライアントがダウンしているというシグナルをどのように受け取るのでしょうか? (クライアントで読み取りまたは書き込みを行わなくても、プローブがクライアントから返信されない場合にシグナルを受け取ると思いました)、オプション SO_KEEPALIVE をオンに設定した後、どのようにプログラムする必要がありますか)。

また、プローブが 3 秒ごとに送信され、その間にクライアントがダウンした場合、クライアントがダウンしていることを認識できず、SIGPIPE が発生する可能性があります。

とにかく重要なのは、コードで SO_KEEPALIVE を使用する方法を知りたいということです。

4

4 に答える 4

22

プローブの数またはプローブ間隔を変更するには、次のように /proc ファイルシステムに値を書き込みます。

 echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time
 echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl
 echo 20 > /proc/sys/net/ipv4/tcp_keepalive_probes

これらの値は、システム上のキープアライブが有効なすべてのソケットに対してグローバルであることに注意してください。また、setsockopt を設定すると、ソケットごとにこれらの設定を上書きすることもできます。リンクしたドキュメントのセクション 4.2 を参照してください。

キープアライブを使用してユーザー空間からソケットのステータスを「チェック」することはできません。代わりに、カーネルは、リモート エンドにパケットの確認を強制し、ソケットが不良になっているかどうかを判断することについて、より積極的です。ソケットに書き込もうとすると、キープアライブがリモート エンドがダウンしていると判断した場合、SIGPIPE が返されます。

于 2011-03-25T16:42:11.653 に答える
11

SO_KEEPALIVE を有効にすると、SO_KEEPALIVE を有効にしない場合と同じ結果が得られます。通常、ソケットの準備ができており、そこから読み取るとエラーが発生します。

Linux では、キープアライブ タイムアウトをソケットごとに設定できます (これは Linux 固有の機能である可能性があります)。システム全体の設定を変更するよりも、これをお勧めします。詳細については、tcp の man ページを参照してください。

最後に、クライアントが Web ブラウザの場合、いずれにせよかなり迅速にソケットを閉じる可能性が非常に高くなります。それらのほとんどは、キープアライブ (HTTP 1.1) 接続を比較的短い時間 (30 秒、1 分など) だけ開いたままにします。もちろん、クライアント マシンが消えたり、ネットワークがダウンしたりした場合 (これは SO_KEEPALIVE が検出に非常に役立ちます)、積極的にソケットを閉じることはできません。

于 2011-03-26T14:28:29.093 に答える
4

すでに説明したように、SO_KEEPALIVE は、何もしていないときでも継続的に接続を検証するようにカーネルをより積極的にしますが、情報が配信される方法を変更したり強化したりしません実際に何かをしようとすると (たとえば「書き込み」)、カーネルが以前に設定されたフラグのステータスを報告するだけなので、すぐにわかります。しばらく待つ必要はありません。ネットワーク アクティビティが失敗するまで数秒 (場合によってはそれ以上) かかります。「反対側が予期せず離れてしまった」状態を処理するために使用したのとまったく同じコード ロジックが引き続き使用されます。変更されるのはタイミングです(方法ではありません)。

ほぼすべての「実用的な」ソケット プログラムは、何らかの方法でデータ フェーズ中にソケットへのブロッキング アクセスを提供します (select()/poll() を使用するか、fcntl()/O_NONBLOCK/EINPROGRESS&EWOULDBLOCK を使用するか、またはカーネルがサポートしている場合)。おそらくMSG_DONTWAITで)。これが他の理由で既に行われていると仮定すると、さらに接続の切断についてすぐに調べるのは簡単です (コードがまったく必要ない場合もあります)。しかし、データ フェーズが何らかの方法でソケットへの非ブロック アクセスをまだ提供していない場合は、次に何かをしようとするまで、接続が切断されたことに気付くことはありません。

(データ フェーズ中に何らかのノンブロッキング動作を行わない TCP ソケット接続は、壊れやすいことで有名です。たとえば、間違ったパケットがネットワークの問題に遭遇した場合、プログラムが無期限に「ハング」するのは非常に簡単です。それについて行うことができます。)

于 2012-09-04T01:29:56.750 に答える