2013-02-23 38 views
0

我正在寫一個多人遊戲,我使用套接字寫我自己的服務器,它在Java中。的Java - 多線程服務器只適用於一個連接

我成功地使用Java教程和一些Google搜索功能來啓動並運行服務器,但是當我試圖實現多線程服務器來處理多個客戶端時,它運行得並不正確。

的第一個客戶端連接仍然會正常工作,但連接將只是坐在那裏,將自己的輸入到服務器後,什麼也不做任何其他客戶端。這裏是我的代碼:

//This class handled Server/client communication for one client. 
public class GameRoom implements Runnable { 
    public GameRoom(Socket socket) { 
    this.socket = socket; 
    } 

    public void run() { 
    logger.info("Game room has been created."); 

    while(true) { 
     try { 
     in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
     out = new PrintWriter(socket.getOutputStream()); 
     String clientResponse = in.readLine(); 
     out.println("You wrote " + clientResponse); 
     out.flush(); 
     } catch (IOException e) { 
     logger.severe(e.getMessage()); 
     throw new RuntimeException(); 
     } 
    } 
    } 

    //Will eventually change the string to a GSON object and delegate the appropriate actions based on the gson object type. 
    private String delegateClientInput(String clientInput) { 
    return "I heard you say: " + clientInput + "\n"; 
    } 

    private BufferedReader in; 
    private PrintWriter out; 
    private Socket socket; 
    private static final Logger logger = LogUtil.initializeServerLog(GameRoom.class.toString()); 
} 

/* 
* This class houses the server socket itself. Handles connecting to multiple clients. 
*/ 
public class ServerClientThreadPool extends Thread { 
    public static void main(String[] args) { 
    ServerClientThreadPool serverClientThreadPool = new ServerClientThreadPool(); 
    serverClientThreadPool.startServer(); 
    } 

    ServerClientThreadPool() { 
    try { 
     serverListener = new ServerSocket(GAME_ROOM_PORT); 
    } catch (IOException e) { 
     logger.severe(e.getMessage()); 
     throw new RuntimeException(); 
    } 
    } 

    public void startServer() { 
    for(int i = 0; i < MAX_CONNECTIONS; i++) { 
     try { 
     GameRoom gameRoom = new GameRoom(serverListener.accept()); 
     gameRoom.run(); 
     } catch (IOException e) { 
     logger.severe(e.getMessage()); 
     throw new RuntimeException(); 
     } 
    } 
    } 

    private static final int GAME_ROOM_PORT = 18000; 
    private ServerSocket serverListener; 
    private static final int MAX_CONNECTIONS = 100; 
    private static final Logger logger = LogUtil.initializeServerLog(ServerClientThreadPool.class.getName()); 
} 

而這裏的客戶端的主要功能,安置在課程的一個單獨的程序:

ClientSocketWrapper clientSocketWrapper = ClientSocketWrapper.createSocketWrapperAndConnectTo("localhost", 18000); 

/** MAIN ENTRY POINT FOR CLIENT */ 
while(true) { 
    clientSocketWrapper.updateInputOutputStream(); 
    clientSocketWrapper.writeToOutputStream(executeClientInputProcessing()); 
    updateGameState(clientSocketWrapper.getServerResponse()); 
} 

我知道你真的不能看到發生了什麼事情在這些方法的內部,但它基本上只是像Java教程那樣實現客戶端,並且它按預期工作。如果您認爲我需要發佈在這裏運行的方法,請告訴我,但我認爲問題出在服務器端。

獎金的問題:如果我在正確的軌道在這裏我也想知道。遊戲相當複雜,但我只是想使用Gson序列化和反序列化對象,並根據發送來的gson字符串來委託適當的操作。谷歌搜索服務器/客戶端架構後,似乎我的方法太簡單了。我很難找到很好的資源來學習更高級的服務器/客戶端架構,所以任何指向偉大的書籍或教程的鏈接都將是一個很大的幫助。

謝謝大家!

回答

3

你不想直接調用gameRoom.run()。這會導致它在當前線程中執行,這將綁定您的服務器循環,直到run()方法完成。相反,你應該在一個單獨的線程中運行它。從Executors工廠類獲得的ExecutorService將是處理該問題的簡單方法。例如,在你的ServerClientThreadPool創建一個ExecutorService:

public class ServerClientThreadPool { 
    private ExecutorService executorService = Executors.newCachedThreadPool(); 

,然後接受socket連接後提交gameRoom到服務:

,我並沒有對ServerClientThreadPool寫 extends Thread上述
GameRoom gameRoom = new GameRoom(serverListener.accept()); 
executorService.submit(gameRoom); 

公告。在上面的代碼中,你沒有以任何方式使用它作爲線程,並且它可能不適合這樣做,除非你需要服務器在其他事情發生的同時接受連接(除了遊戲之外房間,這將已在單獨的線程中處理)。如果您確實需要,那麼它也應該是Runnable,而不是Thread,也應該提交到ExecutorService

基於代碼中關於線程如何工作的明顯混淆,我建議您重新訪問Java "Concurrency" tutorial,其中包括a section on Executors

獎勵:我認爲來回傳遞JSON是一種合理的通信方式。這樣做意味着你不太在意性能,所以我建議你自己停止處理套接字,而是在服務器端使用嵌入式HTTP服務器,在客戶端使用簡單的HTTP客戶端。這將處理所有的套接字和線程廢話給你,釋放你擔心遊戲邏輯的細節。

例如,embedding Jetty是一個簡單的工作,並且有一些功能強大且簡潔的HTTP/REST客戶端,如Apache Http ClientJersey REST Client

+0

謝謝,這個修好了!當然,我需要一個新的線程。我不相信我沒有意識到這一點。 – Slims 2013-02-23 19:10:09

+0

感謝您的額外信息。我希望我能給你更多的讚揚。 – Slims 2013-02-23 19:17:03

+0

@Slims:如果你覺得這是正確的答案,你可以接受:)另外,我爲你添加了一個「獎勵」建議。 – 2013-02-23 19:19:16