87

accept()単純なサーバーを実行していて、クライアントからの接続を編集したとしましょう。

クライアントがいつ切断されたかを知る最善の方法は何ですか? 通常、クライアントはクローズ コマンドを送信することになっていますが、手動で切断したり、ネットワーク接続を完全に失ったりした場合はどうなるでしょうか。サーバーはこれをどのように検出または処理できますか?

4

9 に答える 9

141

TCP では、正常な切断を検出する唯一の方法があります。それは、read()/recv()/recvXXX()読み取り時に戻り値としてゼロを取得することです。

また、切断された接続を検出する信頼できる方法は 1 つだけです。それは、それに書き込むことです。切断された接続に十分な数の書き込みを行った後、TCP は十分な再試行とタイムアウトを行って切断されたことを認識し、最終的に値がwrite()/send()/sendXXX()-1 で、場合によっては「接続がタイムアウトしました」を返します。後者は、接続フェーズで発生する「接続タイムアウト」とは異なることに注意してください。errno/WSAGetLastError()ECONNRESET,

また、適切な読み取りタイムアウトを設定し、失敗した接続をドロップする必要があります。

ここでの答えioctl()FIONREADナンセンスです。ソケットの受信バッファに現在何バイトあり、ブロックせずに読み取ることができるかがわかるだけです。クライアントが 5 分間何も送信しない場合、切断にはなりませんが、FIONREAD0 になります。同じではありません。

于 2013-07-15T22:31:34.070 に答える
15

これをもう少し拡張するには:

サーバーを実行している場合は、TCP_KEEPALIVE を使用してクライアント接続を監視するか、自分で同様のことを行うか、接続を介して実行しているデータ/プロトコルに関する知識が必要です。

基本的に、接続が切断された場合 (つまり、適切に閉じられていない場合)、サーバーはクライアントに何かを書き込もうとするまで気付かず、キープアライブがそれを実現します。または、プロトコルをよく知っている場合は、非アクティブ タイムアウトで切断することもできます。

于 2008-11-12T11:41:12.613 に答える
2

完了ルーチンまたは完了ポートでオーバーラップ (つまり、非同期) I/O を使用している場合、クライアント側が接続を閉じるとすぐに (未処理の読み取りがあると仮定して) 通知されます。

于 2008-11-12T11:49:04.580 に答える
0

EPOLLHUP または EPOLLERR を探してみてください。 クライアント接続がまだ有効であることを確認する方法

0 の読み取りと検索は、場合によっては機能しますが、すべてではありません。

于 2015-12-21T19:22:48.637 に答える
0

TCP には、プロトコルに「開く」手順と「閉じる」手順があります。一度「開く」と、「閉じる」まで接続が保持されます。しかし、データ フローを異常に停止させる可能性があるものはたくさんあります。そうは言っても、リンクを使用できるかどうかを判断する手法は、プロトコルとアプリケーション プログラムの間のソフトウェア レイヤーに大きく依存します。プログラマーが非侵入的な方法 (0 バイトの読み取りまたは書き込み) でソケットを使用しようとすることに焦点を当てたものは、おそらく最も一般的です。ライブラリ内の一部のレイヤーは、プログラマーに「ポーリング」を提供します。たとえば、Win32 asych (遅延) 呼び出しは、エラーなしで 0 バイトを返す読み取りを開始して、それ以上読み取ることができないソケットを通知できます (おそらく TCP FIN プロシージャ)。他の環境では「イベント」を使用する場合があります ラッピング層で定義されているとおり。この質問に対する唯一の答えはありません。ソケットが使用できず、閉じる必要がある場合を検出するメカニズムは、ライブラリで提供されるラッパーによって異なります。ソケット自体はアプリケーション ライブラリの下のレイヤーで再利用できることにも注意してください。そのため、環境で Berkley Sockets インターフェイスをどのように処理するかを理解することをお勧めします。

于 2016-07-19T04:47:46.467 に答える
-3

それは本当に簡単です: 信頼性が高く、面倒ではありません:

        Try
            Clients.Client.Send(BufferByte)
        Catch verror As Exception
            BufferString = verror.ToString
        End Try
        If BufferString <> "" Then
            EventLog.Text &= "User disconnected: " + vbNewLine
            Clients.Close()
        End If
于 2009-10-06T13:43:37.140 に答える
-6

select (読み取りマスクが設定されている) は、ハンドルが通知された状態で返されますが、ioctl* を使用して読み取り保留中のバイト数を確認すると、ゼロになります。これは、ソケットが切断されたことを示しています。

これは、クライアントが切断されたことを確認するさまざまな方法に関する優れた議論です: Stephen Cleary の、ハーフオープン (ドロップ) 接続の検出

* Windows では ioctlsocket を使用します。

于 2008-11-12T09:07:00.897 に答える