- - PR -
CLOSE_WAITについて
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-05-17 15:13
はじめまして。5月からソケット通信を勉強中のものです。
現在、クライアントからサーバーの常駐プログラム(HTTPDなど)を再起動させようと 思っています。再起動自体は上手くいくのですが、その後サーバープログラムを 終了させ、再度起動させようとすると「bind: Address already in use」という メッセージがでてきて起動できません。自分なりに調べた結果、サーバーを netstatしたときに通信をさせているポートがCLOSE_WAITの状態になっている事に 気づきました。 クライアントプログラム自体は socket() connect() send() recv() close() の順番で動作させているだけで、サーバー、クライアント共にcloseしてないという 事はありません。 ソケット通信でのクライアントマシンからサーバーのプログラムの再起動後、CLOSE_WAITが残らないという事はできないのでしょうか。 ご存知の方がいらっしゃいましたら教えて頂きたいと思います。 以下、クライアントとサーバーの送受信部分のソース(C言語)です。 ・クライアント // 受信待ちの状態 while(flg == 0) { if(size = recv(sock, recv_buf, BUFFSIZE - 1, 0) < 0) { perror("recv error"); close(sock); exit(EXIT_FAILURE); } recv_buf[size - 1] = '\0'; printf("1.recv_buf[%s]\n", recv_buf); // ブレイク判定 if(strstr(recv_buf, "END") != NULL) { flg = 1; continue; } printf("<FONT SIZE=\"1\">%s</FONT><BR>\n", recv_buf); strcpy(send_buf, "OK"); if(size = send(sock, send_buf, strlen(send_buf), 0) < 0) { perror("send error"); exit(EXIT_FAILURE); } } close(sock); サーバー // ファイルサイズ分読み込む while(flg == 0) { if(fgets(send_buf, fsize + 1, fp) == NULL) { flg = 1; strcpy(send_buf, "END"); if(size = send(sock, send_buf, strlen(send_buf) + 1, 0) < 0) { perror("send error"); close(sock); exit(EXIT_FAILURE); } continue; } printf("3.send_buf[%s]\n", send_buf); if(size = send(sock, send_buf, strlen(send_buf) + 1, 0) < 0) { perror("send error"); close(sock); exit(EXIT_FAILURE); } if(size = recv(sock, recv_buf, BUFSIZE - 1, 0) < 0) { perror("recv error"); close(sock); exit(EXIT_FAILURE); } if((strcmp(recv_buf, "OK")) == 0) { continue; } fclose(fp); break; } printf("sock closed\\n"); close(sock); break; | ||||||||||||
|
投稿日時: 2006-05-17 16:35
sockopt reuse
などで検索するとハッピーになれるかもしれません。 | ||||||||||||
|
投稿日時: 2006-05-17 17:20
progmanさま
返信ありがとうございました。 キーワードで検索してみるとsetsockoptにSO_REUSERADDRを使えばいけるのでは?と 思いサーバー側のプログラムに以下の記述を追加しました。 しかし相変わらずCLOSE_WAITのステータスのままで、またサーバープログラムを終了後 再度起動しようとしても「bind: Address already in use」のメッセージが表示され 接続できませんでした。setsockoptで設定する第一引数はbindで指定するソケットで 合っているでしょうか・・・? val = 1; val = setsockopt(sock_waiting, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); | ||||||||||||
|
投稿日時: 2006-05-17 20:48
いや、CLOSE_WAITで止まってるのはサーバがcloseしていないからです。 closeすればLAST_ACKに移行します。 インデントが無くて見づらいのでソースを読んでいませんが、 おそらくどこかでブロックしていて、「ここでcloseするはず」と期待している 位置に到達していないのでしょう。 | ||||||||||||
|
投稿日時: 2006-05-18 09:20
ぽんすさま
返信ありがとうございました。 closeする手前で一度printfでcloseを通るかどうかの確認をしていて、そのprintfが 画面に表示されていたので自分としてはcloseしているものと思っていました。 また、このcloseというのはbindやlistenしているソケットではなく、accept時に 生成したソケットをcloseするという認識でよいでしょうか?最初に書くのを忘れて しまったのですが、サーバーはこちらからCTRL+Cやエラーで強制終了させない限り ずっと起動している状態にしています。 今回の現象は一度サーバーをCTRL+Cで終了させ、ソースを修正した後に再度起動 しようと思ったときに発見しました。 ソースをインデントして張り付けたつもりだったのですが、インデントされずに 投稿されてしまいました。申し訳ありませんです・・・ | ||||||||||||
|
投稿日時: 2006-05-18 23:15
bind(2)が失敗するのと CLOSE_WAIT とは別の問題です。
まだ情報が不足してるとゆーか、おそらくご自分で気づいていない 何かが行われています。 bind()でエラーとなってる理由はエラーメッセージの通りのはずで、 典型的にはサーバプロセスを二重起動しようとした際に起きるものです。 CLOSE_WAITについては前回書いた通り。補足すると、通信相手(どちらが サーバとかクライアントとかいうことは関係ない)からFINを受け取った 後で、こちらからFINを投げるまでの間の状態です。 Unixでプロセスを終了した場合にはファイルディスクリプタは 閉じられるので、閉じられていないソケットがあるということは 動いているプロセスがあるはず。
(CLOSE_WAITになっている)TCP接続を終了する、ということであれば accept(2)が返してきたファイルディスクリプタ番号です。
CODEタグを使うとインデントが付いたままとなります。 http://www.atmarkit.co.jp/bbs/phpBB/faq-japanese.php 追記。 CLOSE_WAIT のほうは、「accept()の後、fork()して子プロセスに相手を させるように書いてるんだけど、親プロセスがそのファイルディスクリプタを 閉じてない」とかかなあ... [ メッセージ編集済み 編集者: ぽんす 編集日時 2006-05-19 08:33 ] | ||||||||||||
|
投稿日時: 2006-05-19 09:34
ぽんすさま
返信ありがとうございました。 bindの失敗とCLOSE_WAITが別問題とは思っていませんでした。 というのは、クライアント側PCA(192.168.0.1)とサーバー側PCB(192.168.0.2)で PORT12345で通信させた場合、netstatでサーバー側を見ると以下のように なっていました(サーバープログラムをCTRL+Cで終了させた場合)。
この状態でサーバープログラムを起動させようとすると、12345のPORTが クライアント側の37689というポートに掴まれている為、2重に起動できず 「bind: Address already in use」というエラーが出るという認識だったのですが 間違っていますでしょうか。
実はfork()の使い方をちゃんと理解していないのでfork()は使っていません。 以下にインデントしたサーバーのコードを載せてみましたのでご指摘等あれば 頂けないでしょうか。GetFileSizeというのは自作の関数で、ファイルサイズを返すものです。
[ メッセージ編集済み 編集者: ほいみん 編集日時 2006-05-19 09:35 ] [ メッセージ編集済み 編集者: ほいみん 編集日時 2006-05-19 09:38 ] | ||||||||||||
|
投稿日時: 2006-05-19 22:44
繰り返しますが、CLOSE_WAITで止まっているということは
サーバプロセスがまだ動いていることを意味します。 すなわち、エラーの原因は「サーバプロセスの二重起動」です。 ソースのほうですが、このままではコンパイルも通らない状態ですので printf("waiting...\n"); の次の行の } は無いものと考えます。 気になるところは多いですが、CLOSE_WAITに関して目に付いた箇所だけ。 } else if(size == 0) { の節に入るのはrecv()が0を返したとき、すなわちクライアントから 切断してきた場合です。この節に入ると接続を閉じないまま最外周の whileループの先頭に行くことになるので、サーバプロセスはaccept()で 待ち続けます。それまでのクライアントとの接続は、クライアント側からは すでに閉じられているけれどサーバ側では放置しているのでCLOSE_WAITと なります。 |