ソケット回線断の検出


ぬるぽい  2005-05-19 19:14:00  No: 57457

VC++とは直接関係ないのですが、一応VCで開発してるので
教えてください。現在ソケット通信を使ってデータをやり取りする
プログラムを書いてます。が、回線断の検出で悩んでいます。

動作としては「回線は繋ぎっぱなし」で「必要な時に必要なデータを送る」
動作をしたいので、データが送信されない場合は、常にrecv() = 0でループ
する作りにしています。(このやり方そのものが間違ってたりしますか?)

サーバ側でselect()でループを回し、FD_ISSET()でデータがあればrecv()で
取得。recv()が-1を返せば回線断とみなしてます。
クライアント側のAPL(単純なコンソールアプリ)を強制終了(×ボタン押下)
した場合は、select() = 0/recv() = -1が返り、切断を検出出来るのですが、
強制終了ではなくshutdown()->closesocket()と手順を踏んでアプリを終了
した場合、何故かFD_ISSET()でデータ有り/recv() = 0となり切断を検出
出来ません。

回線断の方法によってrecv()の戻り値が変化する理由がわかりません。
どっちとも回線は切れているのだし。(>_<)。
どなたか回答宜しくお願いします。


いおり  2005-05-19 20:55:52  No: 57458

> 常にrecv() = 0でループする作りにしています。
というのがどういう動作をしているのか良く分かりませんが、
回線が正常に切断された時にrecvが0を返すのは正常動作です。
以下MSDNのrecvの説明より

>If the connection has been gracefully closed, the return value is zero.
訳.もしコネクションが正常に閉じられた場合は、0を返します。

要は返り値がSOCKET_ERRORで異常切断、0で正常切断、それ以外でデータを取得したということです。


オショウ  2005-05-19 22:15:50  No: 57459

この仕様には無理があります。
Win2000/XPのOSで、TCP/IPの仕様上、無通信状態なら約1分半程度
でセッションが切断されます。
レジストリをいじれば当然セッションタイムアウトの時間を変更可能
ですが、実用的ではありません。
無限に接続状態を維持するようなプログラム構造をもたないように、
仕様を変更した方がいいと思いますが・・・

尚、相手がセッションを切断した場合、受信バイト数『ゼロ』での
受信割り込みイベントが発生します。それをもって、切断されたと
判断するのですが・・・

ご検討下さい。

※  

以上。


ぬるぽい  2005-05-19 22:24:37  No: 57460

ご回答ありがとうございます。>いおりさん、オショウさん

>要は返り値がSOCKET_ERRORで異常切断、0で正常切断、それ以外でデータを取得
>したということです。
これが分かりませんでした。「切断」は「切断」で考えてましたので・・・。

>無通信状態なら約1分半程度でセッションが切断されます。
これも知りませんでした。一度セッションが張られたら、
意図的or強制切断するまでは繋がってくれてると考えてました。

>受信バイト数『ゼロ』での受信割り込みイベントが発生します。それをもって、
>切断されたと判断するのですが・・・
どのようにしてこのイベントを取得すれば良いのでしょうか?
すみませんが教えてください。


オショウ  2005-05-20 01:29:41  No: 57461

ソケット通信には、同期通信と非同期通信があります。

ストリームに対する入出力と抽象的に考えるならば、同期通信させるのが
コーディングも楽です。ですが、割り込みイベントはソケットのステータ
スでしか確認できないので、入出力の都度確認して、セッション断の場合
ルーチンを抜けるようなコーディングが必要になります。

非同期通信なら、その受信ルートチンに飛び込んでくるので、受信バイト
数やステータスを確認すれば済みます。

と言うことは、同期通信方式を採用されていると思います。
詳しくはソケット通信の非同期通信の方法を見直して下さい。

以上。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加