- PR -

Socketについて聞きたいです。

投稿者投稿内容
matsuicv
会議室デビュー日: 2006/01/16
投稿数: 2
投稿日時: 2006-01-16 03:50
初めて質問させていただきます。

javaについては、まだ初めて3ヶ月なので、変な質問をしていたら申し訳ありません。

現在、インスタント・メッセンジャー(MSNメッセンジャーなどのこと)を作成しています。クライアントソフト、サーバーサイドプログラミングをともにjavaで作成しているのですが、今回はサーバーについてお聞きしたいです。

症状ですが、サーバーがクライアントが現在ログインしているかをチェックする機能を付けたのですが、場合によってサーバーがフリーズしてしまいます。(通常のログアウトは違う方法を用いている。)


プログラムは以下の通りです。
//==========================================================
while(a==0 && b<3){//3回クライアントに接続を試みます。
try {
System.out.println("LT AOUT UP!:"+member);
System.out.println("IP:"+ip);
int port=10001;
Socket theSock=new Socket(ip,port);//ここでクライアント側にソケットで通信しています。
DataOutputStream sockout=new DataOutputStream(theSock.getOutputStream());//データを渡しています。
String msg="l"+"\n";
sockout.write(msg.getBytes(),0,msg.getBytes().length);//ここで止まっているようです
sockout.close();
theSock.close();
a++;

}catch (Exception e) {
System.out.println("User NOT Found Error:" + e);
a=0;
b++;
e.printStackTrace();
if(b==3){//3回接続に失敗すると、他のプログラムに働きかけ、失敗したクライアントはログアウトする処理が行われます。
w_Login w_log = new w_Login(member,"1");
w_Npre w_npre = new w_Npre(member,"logout"+"\t"+"id"+"\t"+"logout"+"\n");
}
}
}
//ここまで

上記の様なプログラムで、クライアントがログインしているかを確かめています。クライアント側のコンピュータがLAN線が抜けるといった、アクシデントでログアウトした場合は、このプログラムで大丈夫なようです。しかし、クライアントソフトを、ウィンドウズ上のタスクマネージャなどで切られると、サーバーが、プログラム実行中に完全にフリーズしてしまいます。(他のスレッドもあるのですが止まります。)
どうやら、上記プログラム「ここでとまっている」でストップしてしまっていることがわかりました。エラーメッセージも出ません。

わかりにくい質問かもしれませんが、もし答えていただけるようでしたら、よろしくお願いします。
説明で足りない部分があればご連絡下さい。
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2006-01-16 09:33
sotimeoutを入れてみるとか。
しかしサーバ側だと、ServerSocketでaccept()したsocketな気がしますが。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2006-01-16 10:12
ちょっと気になったのですが、サーバーが、特定の通信に対する待機が原因
でフリーズするような設計になっているのは問題かと思いますよ。
ワーカースレッドを起こしてそちらで処理させるとか、ノンブロッキングI/O
を使うなどして、サーバー側のメインスレッドがフリーズすることは避ける
べきかと思います。
流れプログラマ
常連さん
会議室デビュー日: 2005/09/30
投稿数: 26
投稿日時: 2006-01-16 10:13
コード:

theSock.setKeepAlive(true);
theSock.setTcpNoDelay(true);


でいいんじゃないかな? いまいち、自信がありませんが。

KEEP-ALIVE=true で定期的に通信維持用のパケットを送信しますので、通信エラー検出までの時間が短くなります。NO-DELAY=true で、例えばデータ受信時にデータがなければ、すぐ戻ってくるようになります。

-----
yamasa さま
 ご指摘のとおりで、申し訳ありません。
手元にテストできる環境がないため、この発言は撤回します。すみません。

[ メッセージ編集済み 編集者: 流れプログラマ 編集日時 2006-01-16 15:35 ]
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2006-01-16 12:29
setKeepAlive(true), setTcpNoDelay(true) いずれも効果がないと思います。

引用:
KEEP-ALIVE=true で定期的に通信維持用のパケットを送信します


定期的とはどのくらいの間隔でしょうか? 2時間くらいですか? また、その間隔を変更することはできますか?

引用:
NO-DELAY=true で、例えばデータ受信時にデータがなければ、すぐ戻ってくるようになります。


逆に false になっている場合は、すぐに戻ってこないということですね。そのときは、どのくらいで戻ってくるのでしょうか? 0.2秒くらい待たされる感じですか?
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2006-01-16 12:44
せっかく教えてもらったものを、鸚鵡返しに聞き返すのはどうなんでしょう。
自分で調べるステップがないと。
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2006-01-16 14:19
引用:

mioさんの書き込み (2006-01-16 12:44) より:
せっかく教えてもらったものを、鸚鵡返しに聞き返すのはどうなんでしょう。
自分で調べるステップがないと。


これは未記入氏の書き込みに対する反応だと思いますが、
別に未記入氏は自分で調べることをサボっているわけではないですよ。

むしろ、「自信がありません」という言葉を免罪符に妙な回答を書き込む前に、
回答者自身も自分で調べるべきだ、という皮肉だと思いますが。
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2006-01-16 15:32
「サーバーがクライアントが現在ログインしているかをチェックする機能」を実現するには、原則として「アプリケーションレイヤのプロトコルとしてその為の機能を独自に実装する」以外にありません。方法としては、以下の3通りくらいになるでしょう。Aがサーバー、Bがクライアントとします。

・B->Aに定期的にデータを送信する。一定時間B側でデータを受信できない場合切断されているとみなす。
・A->Bにデータを送信する。Bがデータを受信したら、直ちにB->Aにデータを返送する。一定時間内に応答を得られない場合には切断されている。
・送信タイムアウトを調整した後、A->Bにデータを送信する。エラーになった場合には切断されている。

標準的なTCP/IPには非正規な手続きで行われた切断を検出する機能はありません。KeepAliveオプションを有効にすることで検出できますが、実際に通知されるのは数時間後です。しかもSetSockOptでタイムアウト時間を設定することも出来ません。今回の用途ではKeepAliveは約に立たないでしょう。

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