15

私はACベースのLinuxソケットプログラムをデバッグしています。Webサイトで利用可能なすべての例として、次の構造を適用しました。

sockfd= socket(AF_INET, SOCK_STREAM, 0);

connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

send_bytes = send(sockfd, sock_buff, (size_t)buff_bytes, MSG_DONTWAIT);

削除サーバーがサーバープログラムを閉じるときに、切断を検出できます。しかし、イーサネットケーブルを抜くと、send関数は-1ではなく正の値を返します。

サーバー側を変更できないと仮定して、クライアントプログラムでネットワーク接続を確認するにはどうすればよいですか?

4

4 に答える 4

42

しかし、イーサネットケーブルを抜くと、send関数は-1ではなく正の値を返します。

まず第一に、send実際には何も送信しないことを知っておく必要があります。これは単なるメモリコピー関数/システムコールです。プロセスからカーネルにデータをコピーします。しばらくすると、カーネルはそのデータをフェッチし、セグメントとパケットにパッケージ化した後、反対側に送信します。したがってsend、次の場合にのみエラーを返すことができます。

  • ソケットが無効です(たとえば、偽のファイル記述子)
  • 接続が明らかに無効です。たとえば、接続が確立されていないか、何らかの方法ですでに終了しています(FIN、RST、タイムアウト-以下を参照)
  • データをコピーする余地はもうありません

重要な点は、send何も送信しないため、そのリターンコードは、実際に反対側に到達するデータについて何も通知しないということです

質問に戻りますが、TCPがデータを送信するとき、妥当な時間内に有効な確認応答が期待されます。取得できない場合は、再送します。どのくらいの頻度で再送しますか?TCPスタックごとに動作は異なりますが、通常は指数バックオフを使用します。つまり、最初に1秒間待機し、次に2秒間待機し、次に4秒間待機します。一部のスタックでは、このプロセスに数分かかる場合があります。

重要な点は、中断の場合、TCPは、非常に長い沈黙期間の後にのみ接続が切断されたと宣言することです(Linuxでは、15回の再試行(5分以上)のようなことを行います)。

これを解決する1つの方法は、アプリケーションに確認応答メカニズムを実装することです。たとえば、サーバーに「5秒以内に応答するか、この接続が停止していると宣言します」というリクエストを送信してからrecv、タイムアウトを設定することができます。

于 2013-02-08T22:25:27.813 に答える
2

リモート切断を検出するには、次のようにします。read()

詳細については、このスレッドを確認してください。

接続されたソケットの read() 関数はゼロバイトを返すことができますか?

于 2013-02-08T22:21:49.910 に答える
2

write() 関数を呼び出しただけでは、イーサネット ケーブルの抜き差しを検出できません。これは、tcp スタックによる tcp 再送信が無意識のうちに行われているためです。ここに解決策があります。

キープアライブ オプションをアプリケーション ソケットに既に設定していても、アプリケーションがソケットに書き込みを続ける場合、ソケットのデッド接続状態を時間内に検出することはできません。これは、カーネル tcp スタックによる tcp 再送信が原因です。tcp_retries1 と tcp_retries2 は、tcp 再送信タイムアウトを設定するためのカーネル パラメータです。RTT メカニズムによって計算されるため、再送信タイムアウトの正確な時間を予測することは困難です。この計算は rfc793 で確認できます。(3.7. データ通信)

https://www.rfc-editor.org/rfc/rfc793.txt

各プラットフォームには、tcp 再送信用のカーネル構成があります。

Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4)

http://linux.die.net/man/7/tcp

HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval

http://www.hpuxtips.es/?q=node/53

AIX : rto_low, rto_high, rto_length, rto_limit

http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf

切断された接続を早期に検出したい場合は、tcp_retries2 (デフォルトは 15) に低い値を設定する必要がありますが、既に述べたように正確な時間ではありません。さらに、現在、これらの値を単一のソケットに対してのみ設定することはできません。これらはグローバル カーネル パラメータです。単一のソケットに tcp 再送信ソケット オプションを適用する試みがいくつかありましたが ( http://patchwork.ozlabs.org/patch/55236/ )、カーネルのメインラインには適用されなかったと思います。これらのオプション定義がシステム ヘッダー ファイルに見つかりません。

参考までに、以下のように「netstat --timers」を使用してキープアライブ ソケット オプションを監視できます。 https://stackoverflow.com/questions/34914278

netstat -c --timer | grep "192.0.0.1:43245             192.0.68.1:49742"

tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (1.92/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (0.71/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (9.46/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (8.30/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (7.14/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (5.98/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (4.82/0/1)

また、キープアライブ タイムアウトが発生した場合、使用するプラットフォームによってさまざまなリターン イベントに遭遇する可能性があるため、リターン イベントだけで接続不能状態を判断してはなりません。たとえば、キープアライブ タイムアウトが発生した場合、HP は POLLERR イベントを返し、AIX は POLLIN イベントだけを返します。その時点で、recv() 呼び出しで ETIMEDOUT エラーが発生します。

最近のカーネル バージョン (2.6.37 以降) では、TCP_USER_TIMEOUT オプションを使用するとうまく機能します。このオプションは、シングル ソケットに使用できます。

最後に、MSG_PEEK フラグを指定して read 関数を使用すると、ソケットが正常であることを確認できます。(MSG_PEEK は、データがカーネル スタック バッファーに到着したかどうかを確認するだけで、データをユーザー バッファーにコピーすることはありません。) したがって、このフラグを使用して、ソケットが問題なく動作していることを確認できます。副作用はありません。

于 2016-01-25T07:29:23.953 に答える
1

戻り値をチェックし、それがこの値と等しいかどうかを確認します。

EPIPE
このソケットは接続されましたが、接続が切断されました。この場合、sendは最初にSIGPIPEシグナルを生成します。そのシグナルが無視またはブロックされた場合、またはそのハンドラーが戻った場合、送信はEPIPEで失敗します。

また、ハンドラーにSIGPIPEシグナルのチェックを追加して、より制御しやすくします。

于 2013-02-08T22:24:33.187 に答える