質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.58%

C# ソケット通信におけるクライアントの切断確認

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 26K+

score 74

ソケット通信を利用したサーバープログラムを作成しています。
別のサーバープログラムと接続している既存のクライアントシステム(PCではなく専用のハードウェアで動いています)と繋げるものになるのですが、
クライアントが切断した時のサーバー側の挙動で困っている部分があり、ご教示いただきたいです。

各パターンにおける別のサーバの挙動を下記に示します。

①クライアントの電源を落とした場合
即座にサーバー側がソケットの接続をクローズする
電源を付け直して再接続

②クライアントのLANケーブルを抜き差しした場合
LANケーブルを抜いている間はソケットの接続がクローズされず、
LANケーブルを接続しネットワーク認識後にソケットをクローズし、再度接続しなおす。

特に①の部分の仕組みが再現できません。
クライアント側が電源を落としたときにクローズを行っているように感じるのですが、
そもそもクラアイント側がクローズした際にはサーバー側に何か通知のようなものは送られるのでしょうか?
(確認方法はSocketのConnectedだけ?)

下記のようなコードで確認してみたのですが、
電源が落ちているせいか「ClientSocket.Connected == false」の部分が引っかからないようです。

実現方法をお教えいただければ幸いです。

※追記
とりあえずご指定のように接続チェックの前に0バイトのSend呼び出しを行ってみましたが、
クライアント側の電源を落とした後でもConnectedでfalse判定がされません。
ブロック状態で止まっている様子はないのですが・・。

rivate void ThreadMethod(object state)
        {
                                        // クライアントのソケット
            System.Net.Sockets.Socket ClientSocket = (System.Net.Sockets.Socket)state;
int
            try
            {
                while (Form1.SLTAlive)
                {
                    Thread.Sleep(1);

          byte[] tmp = new byte[1];
                    ClientSocket.Blocking = false;
                    ClientSocket.Send(tmp, 0, 0);
                    ClientSocket.Blocking = true;
                    Console.WriteLine(cnt);
                                        //ソケットが接続断またはnullになっていた場合、スレッドを終了させる
                    if (ClientSocket.Connected == false || ClientSocket == null)
                    {
                        //クライアントと切断されました

                        ClientSocket.Shutdown(SocketShutdown.Both);
                        ClientSocket.Close();
                        ClientSocket = null;
                        break;
                    }


                    //略

                }
             }
}
private void ThreadMethod(object state)
        {
                                        // クライアントのソケット
            System.Net.Sockets.Socket ClientSocket = (System.Net.Sockets.Socket)state;

            try
            {
                while (Form1.SLTAlive)
                {
                    Thread.Sleep(1);
                                        //ソケットが接続断またはnullになっていた場合、スレッドを終了させる
                    if (ClientSocket.Connected == false || ClientSocket == null)
                    {
                        //クライアントと切断されました

                        ClientSocket.Shutdown(SocketShutdown.Both);
                        ClientSocket.Close();
                        ClientSocket = null;
                        break;
                    }


                    //略

                }
             }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

0

(確認方法はSocketのConnectedだけ?) 

MSDNのSocket.Connectedプロパティのリファレンスに現在の接続状態の確認方法とそのコード例が載っています。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/08 00:03

    複数クライアントとの接続に対応していれば、電源断から復帰したクライアントの接続には特に支障がないように思うのですが。接続確認している方はそのうち諦めてクローズするでしょうし。
    そのサーバーはクライアントと1対1の接続しか認めないようなシステムなのでしょうか。クライアントの電源断とケーブル引っこ抜きとを判別して処理を変えるのは難しいと思います。

    キャンセル

  • 2016/07/08 07:32

    複数クライアントには対応しているのですが、
    仕様を現存のサーバークライアントと同じにする必要があります。

    上述していますが、クライアントは電源断というよりもハードスイッチのONOFFで電源を落とせます。
    仮に電源OFFしたときにクライアントがクローズ処理をしていたとして、それとコネクションを張っているサーバ側がクローズを検知できるような仕組みがSocketで提供されていないのでしょうか。

    キャンセル

  • 2016/07/08 11:14

    もう少し調べてみたところ、クラアント側の電源ボタンをオフしても、電源コードを抜いても挙動が変わらなかったので
    クライアント側で何かやっているわけではないかもしれません。

    また本文の方に追記を致しました。

    キャンセル

0

別のサーバーシステムが実現できているなら、そっちの通信をパケットキャプチャで覗けませんか?

サーバーからクライアントになんらかのハートビートを送っていたりしませんか?
KeepAliveみたいに。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/08 11:15

    パケットキャプチャができるかわかりませんが、試してみます。

    キャンセル

0

色々試したところ解決しました。

下記サイトを参考にして以下のコードで対応したところ、①、②両方を実現することができました。
http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c

bool SocketConnected(Socket s)
    {
        bool part1 = s.Poll(1000, SelectMode.SelectRead);
        bool part2 = (s.Available == 0);
        if (part1 && part2)
            return false;
        else
            return true;
    }

ですが②におけるLANケーブルの取り外しでなぜ切断を検知できないのか疑問がありますが・・
(今回は仕様だから良かったものの、逆にLANケーブルの切断で接続不可を判断するにはどうするべきか)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/08 14:40

    s.Poll(1000, SelectMode.SelectRead)の戻りは
    Listen が呼び出されており、接続が保留中の場合は true。
    または
    データを読み取ることができる場合は true。
    または
    接続が閉じている、リセットされている、または終了している場合は true。

    切断検知なので1番目はないとして、「データを読み取ることができる場合は true。」とs.Available == 0(読み取れるデータがない)は両立しないから、2つ合わせてみると「接続が閉じている、リセットされている、または終了している場合は true。」だけが判定できるということでしょうか。

    相手がデータを送っていない状態と、ネットワークの先の相手がいなくなってデータが送られてきていない状態の判断ってどうやってるんでしょう?
    LANケーブルの切断と、クライアント側の電源断の違いがきになります。
    サーバーとクライアントで直結しているならともかく、間に1つか2つでも頭のよくない普通のスイッチングハブが入ったらサーバー側からは違いがわからなくなるのではないかと考えていました。

    キャンセル

  • 2016/07/08 15:36 編集

    参考程度にですが接続中の挙動を観察してみました

    1.何もデータを受信していない時
    poll:FALSE, avalaible:TRUE

    2.クライアントからデータを受信した時
    poll:TRUE, avalaible:FALSE

    3.クライアント側の電源をOFFした時
    poll:TRUE, avalaible:TRUE

    4.LANケーブルを切断した時(切断中も)
    poll:FALSE, avalaible:TRUE

    5.LANケーブルを接続しなおし、ネットワークを認証(またはソケットの再接続を開始?)した時
    poll:TRUE, avalaible:TRUE
    (この場合、切断後すぐにクライアントと再接続を行っています)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る