2012-04-25 348 views
2

首先,我不太確定如何解釋,沒有聽起來令人困惑,所以我會盡量簡化。我有一個服務器應用程序,可以將兩個客戶端「配對」,作爲雙人遊戲的一部分。發生的方式是,當第一個客戶端連接到服務器時,套接字連接被接受,則使用該客戶端創建一個新的ClientProtocol線程但未啓動。當另一個客戶端連接到服務器時,他被添加到前一個線程中,然後啓動該線程。該線程知道兩個輸入流和兩個輸出流,每個客戶端一個。但是,當我嘗試從客戶端或服務器端讀取時,沒有任何反應。這適用於單個線程中的單個客戶端。下面是一些代碼:Java客戶端服務器/一個線程多個客戶端

服務器端(主線程)

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

我不確定如果我喜歡你接近這個方式,但是,但是,這兩個客戶端應該得到這些整數。 Wireshark說什麼?數據是否從服務器中傳出? – 2012-04-25 15:51:52

+0

經過一些測試後,似乎有些線程必須互相阻塞。調用ois.available()將掛起在調試器中。 – Renaud 2012-04-25 16:07:59

+0

噢,我預見了你的設計不起作用,但無聊,客戶應該在服務器鎖定一些閱讀電話之前得到他們的意見。 – 2012-04-25 18:01:18

回答

0

訪問資源時必須執行互斥或信號量問題: 您正在使用的流(在本例中爲輸出流和輸入流)正在讀取和寫入相同的資源。 由於所有這些進程都在繼續的一個線程上進行,因此它們的線程正在相互中斷,並在另一個線程上創建等待進程。
一個解決方案是,您在流對象上註冊事件標記,以便每當完成一個事件時,另一個只會啓動。

+0

不存在流從線程的開始到結束。如果我關閉了一個流,我關閉了套接字。 – Renaud 2012-04-25 15:41:22

+0

我不知道我是否理解你所說的「正在讀取和寫入相同的資源」,據我瞭解,objectInputStream和ObjectOutputStream正在寫入和讀取到兩個不同的套接字。它有效,如果我有一個客戶端讀取和寫入到服務器。不過我可能會誤解。 – Renaud 2012-04-25 16:10:14

+0

我只是忘了在這裏調用flush(): public void run(){ 嘗試contester1.getOOS()。writeInt(-1); (); flush(); contester2.getOOS()。writeInt(-2); (); flush(); (例外e){ e。的printStackTrace(); } } – Renaud 2012-04-25 16:20:51

0

你應該循環你的客戶端雙向輸入流。

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

提示:考慮異步網絡與網狀,以獲得更好的性能。