2

以下のコードを使用して、TCP ポートに書き込みを行う C++ アプリケーションにキープアライブ時間を実装します。表示されていませんが、実際に有効な戻りステータスをチェックして、オプションの設定が機能することを確認します。

int option = 1;
int keepalive_intvl = 1;
int keepalive_count = 1;
int keepalive_idle = 1;

setsockopt(the_socket, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof (int) );
setsockopt(the_socket, SOL_TCP, TCP_KEEPINTVL, &keepalive_intvl, sizeof(int));
setsockopt(the_socket, SOL_TCP, TCP_KEEPCNT, &keepalive_count, sizeof(int));
setsockopt(the_socket, SOL_TCP, TCP_KEEPIDLE, &keepalive_idle, sizeof(int));

私のアプリケーションは TCP ポートに書き込みを行っており、1 秒間に数回書き込みを試みています。

// write null packet to determine if connection is still good
return ( send( GetDescriptor(),(char*)NULL, 0, 0 ) != -1 );

他の入力接続を閉じるたびに、上記のテストに基づいて、アプリケーションが接続がダウンしていることを報告するのに 1 分かかります。ハンドラー関数がある場合SIGPIPE、それも呼び出されるまでに 1 分かかります。

私が見たすべてのドキュメントは、キープアライブ パラメーターが分単位ではなく秒単位であることを示しています。しかし、切断された接続を 1 分未満で検出することはできません。

tldp.orgで説明されているキープアライブに関連するシステム変数も変更しようとしましたが、役に立ちませんでした。

echo 1 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 1 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 1 > /proc/sys/net/ipv4/tcp_keepalive_probes

この動作は別のシステム パラメータによって制御されますか? 一部のドキュメントとは対照的に、キープアライブパラメーターは実際には分単位ですか? このタイムアウト パラメータに影響を与える可能性のあるコードで、特定の関数を探す必要がありますか?

4

3 に答える 3

1

あなたの最善の策は、アプリケーション層のキープアライブです。つまり、X 秒ごとにノーオペレーション (NOP) メッセージを送信し、適度に迅速な NOP 確認応答 (NOP-ACK) を期待します。また、リモート接続のクローズが「正常」である場合は、sendすぐにブロックを解除する必要があります。正常でない場合 (ネットワーク要素の障害など)、アプリケーション層のキープアライブは、次回の X+(予想される応答時間) で損失を検出します...

于 2013-03-05T18:50:05.693 に答える
1

値を介して全体的なキープアライブ時間を変更できTCP_LINGER2ます。

入力 tcp プロセスを閉じるたびにnetstat -an、次の行を取得するために使用します。

tcp        1      0 127.0.0.1:32962         127.0.0.1:7780          CLOSE_WAIT  
tcp        0      0 127.0.0.1:7780          127.0.0.1:32962         FIN_WAIT2  

今回は 2 つの方法で変更できFIN_WAIT2ます。

システム レベルでは、このリンクによると、次のようにシステム ファイルを変更することで変更できます。

% cat /proc/sys/net/ipv4/tcp_fin_timeout
60

[To change this to 3 seconds]
# echo "3" > /proc/sys/net/ipv4/tcp_fin_timeout

私の出力 TCP アプリケーションは、接続が約 4 秒でドロップされることを示しています (待機時間は 3、キープアライブ アイドルは 1 だと思います)。

コード内の個々のソケット レベルでこれを変更することもできます。ファイル/usr/include/netinet/tcp.hには、次のように表示されます

#define TCP_LINGER2  8  /* Life time of orphaned FIN-WAIT-2 state */

だから、私のコードに以下を追加すると、

int wait_time = 3;
setsockopt(the_socket, SOL_TCP, TCP_LINGER2, &wait_time,sizeof(int));

システムパラメータを変更するのと同じ効果があります。

アプリケーションレベルのキープアライブが実際に進むべき道であるという点で、他の回答に同意します。そして、ここで述べたように、

RFC 1122、セクション 4.2.3.6 は、データのない TCP キープアライブの確認応答がルーターによって確実に送信されない可能性があることを示しています。これにより、有効な接続がドロップされる可能性があります。さらに、TCP/IP スタックはキープアライブをサポートする必要がまったくない (多くの組み込みスタックはサポートしていない) ため、このソリューションは他のプラットフォームに変換されない可能性があります。

ただし、非テスト環境では、アプリケーション レベルのキープアライブの反対側を実装できる TCP 入力にアクセスできないため、TCP キープアライブが唯一の選択肢になる可能性があります。

于 2013-03-06T18:46:01.443 に答える
1

TCP_KEEPCNT (Linux 2.4 以降) 接続を切断する前に TCP が送信するキープアライブ プローブの最大数。このオプションは、移植性を意図したコードでは使用しないでください。

たぶんそれが理由かもしれません。アプリケーションに独自のキープアライブを実装できますが、それは非常に簡単なはずです。アプリケーションデータまたはキープアライブの「ハートビート」が来ない場合は、もう一方の端を突き始めてください。

于 2013-03-05T18:59:45.097 に答える