10

私は、不確定な時間データを前後にプッシュすることを目的としたクライアント/サーバー関係に取り組んでいます。

私が克服しようとしている問題はクライアント側にあり、切断を検出する方法を見つけることができないということです。

私は他の人々のソリューションで、IO例外をキャッチすることから、3つのSelectModeすべてでソケットをポーリングすることまで、いくつかのパスを取りました。また、ソケットの「Available」フィールドをチェックして、ポーリングを組み合わせて使用​​してみました。

// Something like this
Boolean IsConnected()
{
    try
    {
        bool part1 = this.Connection.Client.Poll(1000, SelectMode.SelectRead);
        bool part2 = (this.Connection.Client.Available == 0);

        if (part1 & part2)
        {
            // Never Occurs
            //connection is closed
            return false;
        }
        return true;
    }
    catch( IOException e )
    {
        // Never Occurs Either
    }
}

サーバー側では、クライアントに「空の」文字(\ 0)を書き込もうとすると、IO例外が強制され、サーバーはクライアントが切断されたことを検出できます(非常に簡単なギグ)。

クライアント側では、同じ操作で例外は発生しません。

// Something like this
Boolean IsConnected( )
{
    try
    {

        this.WriteHandle.WriteLine("\0");
        this.WriteHandle.Flush();
        return true;
    }
    catch( IOException e )
    {
        // Never occurs
        this.OnClosed("Yo socket sux");
        return false;
    }
}

ポーリングを介して切断を検出する際に私が抱えている問題は、サーバーが最後のチェック以降にクライアントに何も書き戻していない場合、SelectReadでfalseにかなり簡単に遭遇する可能性があることです...ここで何をすべきかを確認し、この検出を行うためのすべてのオプションを追跡しましたが、100%は何もありませんでした。最終的に、ここでの目標は、サーバー(または接続)の障害を検出し、クライアントに通知することです。再接続するのを待つなど。これは不可欠な要素であると想像できると思います。

誰かの提案に感謝します。よろしくお願いします。

編集:この質問を見ている人は、以下の答えとそれに対する私の最終コメントに注意する必要があります。この問題をどのように克服したかについて詳しく説明しましたが、「Q&A」スタイルの投稿はまだ作成していません。

4

1 に答える 1

13

1つのオプションは、TCPキープアライブパケットを使用することです。への呼び出しでそれらをオンにしますSocket.IOControl()。唯一の厄介な点は、入力としてバイト配列を使用することです。そのため、データをバイト配列に変換して渡す必要があります。これは、10000msを使用して1000msの再試行で存続する例です。

Socket socket; //Make a good socket before calling the rest of the code.
int size = sizeof(UInt32);
UInt32 on = 1;
UInt32 keepAliveInterval = 10000; //Send a packet once every 10 seconds.
UInt32 retryInterval = 1000; //If no response, resend every second.
byte[] inArray = new byte[size * 3];
Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size);
Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size);
Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size);
socket.IOControl(IOControlCode.KeepAliveValues, inArray, null);

キープアライブパケットは、他のデータを送信していないときにのみ送信されるため、データを送信するたびに、10000msのタイマーがリセットされます。

于 2012-08-06T18:47:16.727 に答える