プロが教える店舗&オフィスのセキュリティ対策術

Linux環境でSocket(dm:PF_INET,type:SOCK_STREAM)を使用しての、
Client&ServerプログラムをCで作成しているのですが、
そこでのSend関数の使い方についてご助力ください。

Client&Serverプログラムは下記のような動きをします。

[Client]
ServerへConnectした後、複数のDataを数秒間隔でServerへ
送信(send関数使用)します。受信(recvやread関数等)は、
一切行いません。

[Server]
ClientからのConnectを受け付けた後、Clientから受信(recv関数
使用)したDataを標準出力へ表示する。送信(sendやwrite関数
等)は、一切行いません。


さて、ここでもしClientプログラムがCloseを発行したり、マシン
DOWN等の理由でConnectionが切断され、Server側のSocketが
CLOSE_WAIT状態になった場合、Bufferに溜まっていたDataを
すべて受けきった後、recv関数が0を返してくれるので
相手が終了したことがわかります。

ここからが質問のMainです。

では、もしServerプログラムがCloseを発行したり、マシン
DOWN等の理由でConnectionが切断され、Client側のSocketが
CLOSE_WAIT状態になっても、CLOSE_WAIT直後のsend関数が
なぜか正常に処理されてしまいます。無論このDataは、
Server側は受け取りません。この次のsend関数実行時に
EPIPEが返ってくるので、ここでようやくSocketが切断された
ことが判ります。

これを何とかCLOSE_WAIT状態になった直後から、send関数で
切断を検知できるようにできないでしょうか。

よろしくお願いします。

以上

A 回答 (4件)

#3です。


>完全な保証ではないのですが、”送れた/送れない”をきちんと
ログとして残す必要があるのです。

なるほど、そういう事情でしたか。それだと、それなりの信憑性が要求されますね。

>それと最初にご提案いただいたrecvをNonBlockモードで呼び出す
方法ですが、これだとrecvのリターン値は0が返ってこないでしょうか?

Linuxで以下のような、プログラムを組んで確認しました。

//送信前に、ノンブロッキングでrecvする。
ret = recv(sock,rbuf,sizeof(rbuf),MSG_DONTWAIT);
if (ret == -1 && errno == EAGAIN){
//正常なので送信可能
ret = send(sock,msg[i],sendlen,0);
if (ret != sendlen){
//送信エラーの処理
}
}else{
//切断検知時の処理
 // CLOSE_WAITになると ret=0が返る
}

サーバー側で切断時、直ちにrecvで戻り値=0となり、エラーの検知ができました。ret==-1 かつ errno==EAGAIN
であれば、回線は正常状態です。
    • good
    • 1
この回答へのお礼

プログラムを組んでまで、確認していたいたのですね。
多謝多謝です。

やはりSendだけでは、厳しそうですね。
tatsu99さんの案も候補にして、今後の方針を探って
いこうとおもいます。

ありがとうございました。

お礼日時:2005/09/19 11:33

すみません。

全然回答になっていないんですが、
>これから作ろうとしている本プログラムでは、実はもっと送信量は
増えるんです。このプログラムは常時接続型を考えていまして、
めったに切断は起こりません。

ということであれば、
CLOSE_WAIT状態になった直後のsend関数で切断を検知できなくても、次のsendで、切断が検知できますので、運用上は特に、問題ないと思うのですが、いかがでしょうか。
CLOSE_WAIT状態になった直後のsend関数で、必ずエラーを検知することに、こだわる必要性がわかりません。できましたら、その理由を教えていただけませんでしょうか。(何故、次のsendでのエラー検知ではいけないのでしょうか)

この回答への補足

幾度も返信いただきありがとうございます。

>CLOSE_WAIT状態になった直後のsend関数で切断を検知できなくても、
>次のsendで、切断が検知できますので、運用上は特に、問題ないと
>思うのですが、いかがでしょうか。

実は、データの保証をしないといけないという事情があります。
完全な保証ではないのですが、”送れた/送れない”をきちんと
ログとして残す必要があるのです。

それと最初にご提案いただいたrecvをNonBlockモードで呼び出す
方法ですが、これだとrecvのリターン値は0が返ってこないでしょうか?
それにしても、Winsockだとただしくエラーが検知できてWSAESHUTDOWNの
エラーコードが取得できるのに、なぜUnixだとだめなんでしょうか。
って愚痴ってもしょうがないですね。

何かよい方法があればお願いします。
よろしくお願いいたします。

補足日時:2005/09/16 11:51
    • good
    • 0

>この次のsend関数実行時に


EPIPEが返ってくるので、ここでようやくSocketが切断されたことが判ります。

この次のsend関数実行迄に、相当の時間間隔が発生する為、もっと素早く、障害を検知したいということであれば、以下の方法で対処できるはずです。

まず、ソケットをノンブロッキングモードにします。
次に、一定間隔でrecv関数を呼び出し、サーバーからのデータを受信します。もちろん、サーバはデータを送ってないので、「データなし」の状態が、続きます。しかしながら、Connectionが切断された場合は、recv関数からエラーが返ります。

この回答への補足

返信ありがとうございます。

recv関数をノンブロッキングモードで呼び出すことは、一応考えました。
でも、質問にある
『複数のDataを数秒間隔で・・・・』
というのは、実はテストプログラムなんです。
これから作ろうとしている本プログラムでは、実はもっと送信量は
増えるんです。このプログラムは常時接続型を考えていまして、
めったに切断は起こりません。めったにおきない現象のために、
余計な処理を増やしたくないということもあります。

なんとかないでしょうか、send関数で判定する方法。
それともあきらめるしかないのでしょうか。

わがままで申し訳ありませんが、よろしくお願いします。

補足日時:2005/09/16 09:37
    • good
    • 1

>CLOSE_WAIT直後のsend関数が


>なぜか正常に処理されてしまいます。無論このDataは、
>Server側は受け取りません。この次のsend関数実行時に
>EPIPEが返ってくるので、

このあたりの表現が気になるのですが、send のリターン値をちゃんと見ていますか?非負で引数で与えたデータ長より小さい値が返ったら残りデータを再度sendしなければなりません。そのとき-1が返るのでは?

この回答への補足

返信ありがとうございます。

sendのリターン値は、ちゃんと判定しています。

>CLOSE_WAIT直後のsend関数が
>なぜか正常に処理されてしまいます。
このときも、ちゃんとリターン値を判定しています。
このときsendの引数に渡したLengthSizeと同じ
値が返ってきてしまいます。

よろしくお願いします。

補足日時:2005/09/16 09:33
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています