2012-04-25 25 views
2

まず第一に私はそれをどのように混乱させることなく説明するかわからないので、簡単にしようとします。私は2人のゲームの一環として2人のクライアントを一緒に「ペアにする」サーバーアプリケーションを持っています。方法は、最初のクライアントがサーバーに接続し、ソケット接続が受け入れられ、そのクライアントで新しいClientProtocolスレッドが作成され、開始されていないことです。別のクライアントがサーバーに接続すると、前のスレッドに追加され、スレッドが開始されます。スレッドは、クライアントごとに1つずつ、2つの入力ストリームと2つの出力ストリームを認識します。しかし、クライアント側またはサーバー側から読み取ろうとすると何も起こりません。これは、単一のスレッド内の単一のクライアントでうまく動作します。ここではいくつかのコードは次のとおりです。Javaクライアント/サーバ/ 1つのスレッド複数のクライアント

サーバー側(メインスレッド)

public static Queue<ContestProtocol> contesters; 

public static void main(String[] args) throws IOException { 
    ServerSocket serverSocket = null; 
    contesters = new LinkedList<ContestProtocol>(); 

    try { 
     serverSocket = new ServerSocket(4444); 
    } catch (IOException e) { 
     System.err.println("Could not listen on port: 4444."); 
     System.exit(-1); 
    } 

    while (true) { 
     Socket socket = serverSocket.accept(); 

     ObjectInputStream ois; 
     ObjectOutputStream oos; 

     try { 
      ois = new ObjectInputStream(socket.getInputStream()); 
      oos = new ObjectOutputStream(socket.getOutputStream()); 

      synchronized (contesters) { 
       if (contesters.size() == 0) { 
        Contester contester1 = new contester(ois, oos); 
        contesters.add(new ContestProtocol(contester1)); 
       } else { 
        Contester contester2 = new Contester(ois, oos); 
        contesters.poll().hook(contester2).start(); 
       } 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

サーバ側(ContestProtocol)

private Contester contester1, contester2; 

public ContestProtocol(Contester contester1) { 
    super("ContestProtocol"); 
} 

public ContestProtocol hook(Contester contester2) { 
    this.contester2 = contester2; 
    return this; 
} 

public void run() { 
    try { 
     contester1.getOOS().writeInt(-1); 
     contester2.getOOS().writeInt(-2); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

サーバ側(contester):

public Contester(ObjectInputStream ois, ObjectOutputStream oos) { 
    this.ois = ois; 
    this.oos = oos; 
} 

public ObjectInputStream getOIS() { 
    return ois; 
} 

public ObjectOutputStream getOOS() { 
    return oos; 
} 

クライアント側:

try { 
      socket = new Socket(serverAddr, 4444); 
      oos = new ObjectOutputStream(socket.getOutputStream()); 
      ois = new ObjectInputStream(socket.getInputStream()); 
      int selectedChampion = ois.readInt(); 
} catch (Exception e) { 
       e.printStackTrace(); 
} 

ContestProtocolスレッドは問題なく実行されますが、両方のクライアントはreadInt()でハングします。私はなぜなのか理解していない。

+0

私はあなたがこれに近づいているのが好きかどうかはわかりませんが、それにもかかわらず、2人のクライアントはそれらのintを取得する必要があります。 Wiresharkは何を言いますか?サーバーからデータが出ていますか? –

+0

いくつかのテストの後、いくつかのスレッドが互いにブロックしているように見えます。 ois.available()の呼び出しはデバッガで停止します。 – Renaud

+0

ああ、私は仕事をしないようにあなたのデザインをエキスパートしましたが、ちょっとしたことがあっても、クライアントは何らかの読み取り呼び出しでサーバーがロックされる前にintを取得していたはずです。 –

答えて

0

これは、リソースにアクセスする際にミューテックスまたはセマフォの問題を発生させる必要があります。 使用しているストリーム(この場合は出力ストリームと入力ストリーム)は、同じリソースを読み書きする必要があります。 これらのプロセスはすべて1つのスレッドを続行しているので、それらのスレッドは互いに中断してお互いに待機プロセスを作成しています。
解決策の1つは、ストリームオブジェクトにイベントライザーを登録するため、一方が終了するたびに他方が開始されることです。

+0

ストリームは、スレッドの最初から最後まで生き続けません。ストリームを閉じると、ソケットを閉じます。 – Renaud

+0

objectInputStreamとObjectOutputStreamは、2つの異なるソケットに書き込みと読み取りを行っていることを理解している限り、「同じリソースへの読み書きをしています」と言っていることを理解しているかどうかはわかりません。これは、単一のクライアントがサーバーに読み書きをしている場合に機能します。私は間違っているかもしれない。 – Renaud

+0

flush()をここで呼び出すことを忘れてしまった: public void run(){ try { contester1.getOOS()。writeInt(-1); contester1.getOOS()。flush(); contester2.getOOS()。writeInt(-2); contester2.getOOS()。flush(); } catch(例外e){ e。printStackTrace(); } } – Renaud

0

クライアント側の入力ストリームをループする必要があります。

while(true){ 
if(ois.avaible() > 0) 
ois.readInt(); 
} 

ヒント:パフォーマンスを向上させるために、nettyを使用して非同期ネットワークを調べます。

関連する問題