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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

3回答

40483閲覧

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

ryo_se

総合スコア68

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2016/07/07 09:59

編集2016/07/08 02:12

ソケット通信を利用したサーバープログラムを作成しています。
別のサーバープログラムと接続している既存のクライアントシステム(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; } //略 } } }

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

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 04:53

ryo_se

総合スコア68

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kopio

2016/07/08 05:40

s.Poll(1000, SelectMode.SelectRead)の戻りは Listen が呼び出されており、接続が保留中の場合は true。 または データを読み取ることができる場合は true。 または 接続が閉じている、リセットされている、または終了している場合は true。 切断検知なので1番目はないとして、「データを読み取ることができる場合は true。」とs.Available == 0(読み取れるデータがない)は両立しないから、2つ合わせてみると「接続が閉じている、リセットされている、または終了している場合は true。」だけが判定できるということでしょうか。 相手がデータを送っていない状態と、ネットワークの先の相手がいなくなってデータが送られてきていない状態の判断ってどうやってるんでしょう? LANケーブルの切断と、クライアント側の電源断の違いがきになります。 サーバーとクライアントで直結しているならともかく、間に1つか2つでも頭のよくない普通のスイッチングハブが入ったらサーバー側からは違いがわからなくなるのではないかと考えていました。
ryo_se

2016/07/08 06:37 編集

参考程度にですが接続中の挙動を観察してみました 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 (この場合、切断後すぐにクライアントと再接続を行っています)
guest

0

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

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

投稿2016/07/07 23:39

kopio

総合スコア487

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryo_se

2016/07/08 02:15

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

0

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

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

投稿2016/07/07 10:35

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryo_se

2016/07/07 11:06 編集

Connectedは最後の接続状態から判断するものなんですね、知りませんでした。 ただ参照サイトに書いてある現在の接続状況の確認方法では、 ②のパターンでLANケーブルの再接続前に接続断を行ってしまうように見受けられます (現在確かめられる環境にいないため推測になってしまいますが・・)
catsforepaw

2016/07/07 12:45 編集

接続断を1回だけで判定せずに、何度も繰り返して一定時間未接続状態が続いたらクローズで良いように思うのですが。
ryo_se

2016/07/07 14:31

すみません、書き方が悪かったみたいです。 ①と②を両方同時に実現したいのです。 そのため、おっしゃているやり方だと今度は①ができません。 実際に別のサーバーシステムはこのように動いているので何かしらの方法があると思うのですが・・。(ブラックボックス状態なので中の仕組みはわかりません) ちなみに終了電文のようなものをクライアントから受け取っている挙動はないので、そこから判断しているということはないと思います。 クライアントの電源をただ落としただけならば、LANケーブルを外した時と同じようになるように思えるので、何かしらの方法があると思うのですが・・。
catsforepaw

2016/07/07 15:03

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

2016/07/07 22:32

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

2016/07/08 02:14

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問