- PR -

netstatのstateがCLOSE_WAITでstop

投稿者投稿内容
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-04-06 11:28
ネットワークに関し、初心者です。
ソケットを用いてサーバーとデータを送受信しています。
socket()
connect()
send()
recv()
close()
の流れでデータを送信しています。この繰り返しです。
エラーでとまっていたのでnetstatコマンドで確認したとことろ

proto Recv-Q Send-Q LocalAddress Foreign Address State
tcp 1 0 省略      省略 CLOSE_WAIT

のままずーと変化なしでとまっています。
このような状態になるのはどんな時なのでしょうか?
FINを受信し、LAST_ACKへ遷移するとありますが、遷移せずとまってしまっています。
データの送信は約10秒に1回、約16Kbyteで連続運転10日以上で一度おきました。
再現はしていません。
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2005-04-06 12:46
同じく初心者ですけど

相手側がなんらかの理由ですでに閉じているから CLOSE_WAIT になっている
わけですよね。で、相手が閉じているものだから期待した通りにはコトが
進まないのでプログラムがエラーを出している、と。でもって、そのエラーを
検知したときに終了せずにそのまま止まるようにプログラムが書かれているので
いつまで経ってもソケットが閉じられず、CLOSE_WAIT になっているのでは
ないでしょーか。
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2005-04-07 18:16
現象を見るに、通信相手が先に close(shutdown) しているのに、こちら側で気付かず、close(shutdown) を行っていないようですね。

具体的な話は、動かしているプログラムのソースと、通信の際のプロトコルが分からないと何ともいえないと思います。

ただ、疑問点として、

・双方向通信のプログラムなのに select等での制御は行ってないのでしょうか?
・各 recv から次の処理に進む際に、データの受信漏れは無いでしょうか?

というところが引っかかります。
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-04-19 11:02
すみません、
随分、留守にしていたので、なかなか見れませんでした。
recv()のとき、FIN (受信サイズ0)待ちの時も、通常のデータ受信の時も
selectでタイムアウト(10秒)は入れているのですが。
データのサイズもチェックしています。
相手側はcloseはしているようなのですが。
recv()のときデータの後ろにゴミがあっても、size_t で指定したサイズより
大きいものは受信しないと思っているのですが?


recvの部分だけですが、、、下に書きます。
rc>len の条件が抜けているのですが。
ソケットやサイズは、別のところで作成しています。

timeout.tv_sec =10;
timeout.tv_usec = 0;
int count;
int flg= 0;

fd_set mask; // read set
fd_set r_set; // read set

FD_ZERO(&mask);
FD_SET(s,&mask);

while(1){
r_set = mask;
if ((count = select(s+1, &r_set, NULL, NULL, &timeout))== -1){
fprintf(stderr,"Select error !!(recv)\n");
return RET_NG;
}
else if (count ==0){
fprintf(stderr,"Time out !!(recv) socket = %d\n",s);
return RET_NG;
}

/*パケット受信*/
if(FD_ISSET(s,(fd_set *)&r_set)) {
if(flg==0) {
// printf("Receive message : ");
flg=1;
}
rc=recv(s,inbuf,len,flags);
// printf("recv size= %d\n",rc);

}
if(rc == len){

break;
}
/*正常終了*/
if(rc == 0){
return RET_FIN;
}
if(rc < len){ // error -1 含む
// printf("受信電文短\n");
return RET_NG;
}

}
return RET_OK;
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2005-04-20 00:59
ソースコード拝見しました。

こちらは、受信処理の部分のみを関数として切り出して、状況に応じて返り値を変えているのですね?
kuri2 様が想定している、アプリケーションレベルでの通信プロトコルが分からないので、return した後のソケットの処遇が気になるところです。特に NG だった時に。

それと、どうやら recv の返り値の扱い、つまりデータサイズチェックにやや問題があるように見受けられます。
というのも、recv によってバッファが一杯になるかどうかは不定にも関わらず、バッファが一杯でない時をエラー扱いしているからです。
(ただ、flag の値によっても、話はかわるのですが…)

詳しくは、recv(2)の MSG_WAITALLフラグ、select_tut(2)の「SELECTの掟」5項、プログラミング系Q&Aの3項をご参照ください。
※MSG_WAITALL については、「使え!!」と主張している訳ではないです…

結局のところTCPレベルの受信操作では、「相手からこれ以上データが来る可能性があるかどうか」( recv の返り値が 非 0 か 0 か )しか判断できないので、やはり通信のプロトコルそのものが明らかにならないと、何とも言えませんね…。

[ メッセージ編集済み 編集者: angel 編集日時 2005-04-20 02:14 ]
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-04-20 10:28
angel 様 どうもありがとうございます。

アプリケーションレベルでは、リターンの後、OK,NGにかかわらず、close()しています。
OKの時だけ、受信データをチェックしています。値がおかしい時は再送しています。
recvのflagは何も設定していません。flag=0 です。
flagについてもう少し、勉強します。
相手からくるサイズは、固定です。
すみません、わかりにくい文章で。
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2005-04-20 12:23
何で返ってきてもclose()するはずなのに CLOSE_WAIT で止まっている、
ということでしょうか。
とりあえず、どこで止まっているか調べるところからはじめるんじゃあ
ないでしょーか。 ログを書いておかないと厳しいと思います。
エラーのときはその内容も取得して。あと、ログはwrite(2)で書いて
おくのが無難です。高級な関数を使ってると、ログに書く内容が
なかったのか、バッファにたまったまま止まっているのか、どっちなんだ?
などと余計なところで悩んだりするので。
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2005-04-20 12:44
今のところ私が怪しいと思っているのは、

・kernel レベルでは、全データを受信し、FIN も受信した
・なので、プログラムが全データを recv し、close/shutdown を行えば、kernel も FIN を送信できる
・しかし、プログラムは一部のデータのみを recv し、close をしてしまった
・close は、厳密には FIN を送る操作ではないため、未 recv データが残っていることも重なって、CLOSE_WAIT 状態のまま止まっている

という筋書きです。裏が取れてないので憶測の域を出ませんが。
明示的に shutdown を使用していれば問題も無いと思うので、それで回避した方が良いようにも思いますがね。

スキルアップ/キャリアアップ(JOB@IT)