- PR -

while(ture)実行時にほかのメソッド呼び出すことは可能ですか?

1
投稿者投稿内容
かな
会議室デビュー日: 2006/01/26
投稿数: 2
投稿日時: 2006-01-26 23:11
はじめまして。かなといいます。プログラム経験がほとんどない初心者ですがよろしくお願いします。

質問ですが、その前にまず、どういうことをしているかというと、A.java, B.javaと2つのクラスがあります。
A.javaでは、
private void A1(){
try{
while(true){
socket=serversocket.accept();//サーバソケット接続待ち
socket.start();
}
}catch(IOException e){
クローズ処理

と、
private void A2(){
serversocket.close();//サーバソケットをクローズする
}
があるとします。

そして、B.javaでA1を実行して、サーバが接続待ちをしている状態で(while(true)が動いている状態で)A2を呼んでサーバソケットをクローズすることはできないのでしょうか?

実はこのようにしたところ実行することができませんでした。できない場合は別のやり方を考えなければならないのですが、このような処理ができるのかどうかを書いている本や、ネットのページをみつけられませんでした。

分かる方がいらっしゃいましたら教えてください。お願いします。
未記入
常連さん
会議室デビュー日: 2004/08/21
投稿数: 41
投稿日時: 2006-01-27 00:06
別スレッドからcloseしてあげればよいのではないでしょうか?
tmp
会議室デビュー日: 2006/01/12
投稿数: 11
投稿日時: 2006-01-27 01:17
はじめまして。
私も勉強中なのでjava.net関連は疎いですが、
書き込ませていただきます。

結論から申し上げますと、可能(なはず)です。
("serversocket.accept()"とか呼び出してますし…)

かな様がおっしゃっている、
引用:

実はこのようにしたところ実行することができませんでした。


…についてはどんな状況か分からないのですが、
ソースを拝見したところ、4点ほど問題がありそうです。

@いきなりコンパイルエラー?
この場合、B.javaからa.A1()、a.A2()みたいな呼び方をするのであれば
修飾子は"private" ではなく "public"(同一packageならprotectedもOK)
にする必要があります。

A実行途中、原因不明でプログラムが終了?…
"try { 〜 } catch" にIOExceptionだけでなく、
"java.net.SocketException" など、ネットワーク通信中に
発生する可能性のある例外(よくわからなければ
とりあえず"java.lang.Exception"でも良いと思います。)
をキャッチするようにソースを編集し、実行してみて
なぜ実行できなかったか調べる必要があります。

Bソケット接続待ち?
サーバプログラムが起動しているのとは
別のマシン上のクライアントからサーバへ接続し、
クライアント 〜 サーバ接続中にLANケーブルを引っこ抜いてみて下さい。
この時ネットワーク障害のため発生した例外をキャッチするはずです。
→ということは、正常時「while(true) { 〜 } 」間では
障害が発生しなかったため catch 節中のクローズ処理まで
処理が到達していなかった、
といった結論になるのではないかと思います。

Cそもそも「while(true)」内でメソッドを呼び出していない。
例のソースでは「while(true)」内にメソッド"A2()"と書かれていません。
表題に対する答えは次のようになると思います。

●サンプル
 while(true){
  try{
   socket=serversocket.accept();//サーバソケット接続待ち
   socket.start();
   …中略…
   // 色々な処理をした後ソケットクローズ
   socket.close();
  }catch(Exception e){
   // サーバクローズ処理
   a.A2();
   // 必要なら while から抜け出す。
   break;
  }
 }

@〜C、すでに実施されていたら板汚してしまい申し訳ありません…

以上、よろしくお願い致します。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2006-01-27 05:05
「実はこのようにしたところ実行することができませんでした。」というのが具体的に何をしたのか示してはいかがでしょうか。
既にほかの方が書かれている通り、accept() の実行中に別のメソッドを呼ぶということでしたら別スレッドから呼んでやる必要がありますね。
すでに別スレッドから呼び出す方法を試してうまくいかないのであればどのようにうまくいかないのかを示す必要があるかと。
かな
会議室デビュー日: 2006/01/26
投稿数: 2
投稿日時: 2006-01-27 22:23
ありがとうございます。
tmpさんのご指摘ですが、
@すみません、こちらに書くときに移し間違えました。publicにしています。
ANullpointeExceptionだったです。
B正常時はwhile(true)からぬけることはないですね。
Cこれは私の説明が悪かったです、、、catchの中でA2()を呼び出したいのではなく、while(true)を抜けるためにA2()を呼び出したいと思っています。なので、acceptのところでExceptionをだすとか、while(true)をwhile(isFlg(boolean型))などにして、A2()でisFlgを変えることでループを抜けるようにしたかったのです。

私の説明が悪かったので、もう1度説明します。

まず、あるサーバの起動や停止時に行う処理を書いたクラスをInitilzr.javaとします。そして、サーバの起動時にサーバソケットを生成し、クライアントソケットからの接続待ちをするのですが、それを記述したものがManager.java, ManagerThread.java,となります。

問題ですが、サーバ停止時にサーバソケットをクローズする処理がないため、サーバソケットが接続待ちしたままになっており、次にサーバを起動したとき(あるいは再起動をしたとき)にAddress already in use(port番号がすでに使われている )となってしまうことです。

Manager.javaですが、

public static final ThreadGroup currentThreads = new ThreadGroup("ThreadManager");
public void makesocket(){
try {
while (true) {
socket = serverSocket.accept();
new ManagerThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(serverSocket!= null)
try {
serverSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}

のようになっています(抜粋)。

そして、ManagerThread.javaは
//コンストラクタ
public CgsmManagerThread(Socket socket) {
this.socket = socket;

}
//ソケットの処理
public void run() {
log("接続処理スレッド起動!!!");
//接続可能セッション数のチェック
if (reachedMaxSession()) {
log("Agentからの接続セッション数が上限を超えているため、通知を破棄しました。");
try {
//強制的に通信を切断
socket.close();
} catch (IOException e) {

}
//終了
return;
}
(略:MD5などでの認証を行っている)

//接続可能数チェックメソッド
private boolean reachedMaxSession() {

int numThreads;
Thread[] listOfWaiters;
numThreads= Thread.activeCount();
listOfWaiters = new Thread[nu];
Thread.enumerate(listOfWaiters);
int count = 0;
for (int i = 0; i < listOfWaiters.length; i++) {
if (listOfWaiters[i] instanceof CgsmManagerThread) {
count++;
}
}
if (count > 4) {
return true;
}
return false;
}

のようになっています。

また、Manager.javaのなかに、
publoic void closesocket(){
if(serversocket != null){
serversocket.close();
}
}
として、Initilzr.javaのサーバ停止を行うメソッド内に入れたのですが、NullPointerExcepiton?が出てしまい、処理がとまってしまいました。また、上記のとおり、while(isflag)として、サーバ停止時にソケット(クライアント)を生成し、フラグを変えるようにしたのですが、フラグが反映されずに、ループをぬけられませんでした。

でどうにかして、while(true)から抜け出し、serversocketをクローズすることで、サーバ起動時にAddress already in useと出ないようにしたいのですが、できません。

どなたか分かる方がいらっしゃいましたら、お力を貸していただきたいです。よろしくお願いします。
未記入
常連さん
会議室デビュー日: 2004/08/21
投稿数: 41
投稿日時: 2006-01-28 13:31
if(serversocket != null){
serversocket.close();
}
のserversocketはManager.javaのserverSocketでしょうか?
whileループ中の処理の中の変数を外部から変更してそれが処理に反映されない場合、
私の場合はその処理をスレッド化してwhileループの最後にThread.sleep(0);
を記述すると上手く反映されるようになりました。
いづれにせよManager.javaのserverSocketを別処理からclose(又は実行中別処理から
フラグの値を変えるなど)してwhileを抜けたいわけですからmakesocket()又はその処理
をスレッドとして実行しないといけないと思います。


[ メッセージ編集済み 編集者: matsu_on 編集日時 2006-01-29 01:20 ]
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2006-01-29 17:07
こんにちは。

私はしばしばこの類のサーバを記述します。

別スレッドから、serversocketをclose()
したこともあります。
その方法で確かに終了するのですがIOExceptionが
出て気持ち悪いです。
※NullPointerExceptionということは、なにか
 別にも問題があるのでは?

私なら、accept()を呼び出す前に serversocketに
タイムアウト時間を設定しておきます。

タイムアウトしたときは再び acceptを
繰り返します。
ただし、ループの先頭で、終了要求フラグを
チェックして、要求があればループを脱出
し、サーバソケットをクローズします。

停止要求を行うスレッドから呼び出される、
A2()に相当するところで終了要求を立てる
だけを行います。
Solarisを使用しているなら、サービススレッド
に対して interrupt()を行うと停止を速くできる
効果があります。
Solaris以外の OSでは interrupt()の効果がない
ものもありますが、害が無いので入れておきます。

タイムアウト時間は状況に応じて数百ミリ秒〜
数十秒です。
停止要求から停止までの時間と、負荷のバランス
を考慮して値を決定します。

かなさんの場合に適用できるかわかりませんが、
多くの場合これで行けると思います。
1

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