2010-10-03 114 views
3

我正嘗試使用java套接字創建客戶端服務器遊戲。我有一個線程服務器來控制遊戲的邏輯。我也有客戶端線程與服務器通信。我使用多個客戶端處理程序線程來促進服務器到客戶端的通信。我使用多個線程使用套接字與其他客戶端線程進行通信。如何促進服務器線程和Java中的多個客戶端線程之間的通信

現在,我有一個如何促進服務器線程和多個客戶端線程之間的通信問題。例如,如果服務器選擇下一個播放器進行播放,那麼它應該如何指示客戶端處理程序線程,並通過套接字與客戶端線程進行通信?

回答

1

我懷疑你的客戶端線程掛在阻塞讀取操作上。要「釋放」這些線程並使它們發送數據,您必須通過thread.interrupt()來中斷它們。 (這將導致閱讀拋出一個InterruptedException阻塞。)

不過,我已經寫了一些網絡遊戲的自己,我會真的建議你看看到java.nio packages,尤其是Selector。使用這個類你可以很容易地讓整個服務器成爲單線程的。當涉及到同步所有這些客戶端線程時,這會爲您節省一大筆頭疼的

0

我認爲使用像ActiveMQ這樣的現有通信基礎設施將會非常有用,可以處理低層次的管道問題,並且讓您能夠在更高的概念級別解決遊戲設計問題,而不是處理低級錯綜複雜的問題。

這就是說。如果我瞭解你,那麼你有一個遊戲客戶端與多個線程,其中一個處理通信到服務器。在服務器上,每個客戶端和遊戲服務器邏輯都有一個通信線程。

我只會使用套接字進行遠程通信和隊列進行服務器線程之間的通信。在隊列中來回發送不可變對象(或拷貝),所以你不需要同步對消息中數據的訪問。作爲同步的基礎,您可以阻止Socket或BlockingQueue,然後您不需要手動同步,但這需要仔細的協議設計。

4

我已經按照以下方法完成了此操作。我有一個服務器插槽

public Server(int port, int numPlayers) { 
    game = new PRGameController(numPlayers); 

    try { 

     MessageOutput.info("Opening port on " + port); 
     ServerSocket clientConnectorSocket = new ServerSocket(port); 
     MessageOutput.info("Listening for connections"); 

     while (!game.isFull()) { 
      // block until we get a connection from a client 
      final Socket client = clientConnectorSocket.accept(); 
      MessageOutput.info("Client connected from " + client.getInetAddress()); 

      Runnable runnable = new Runnable() { 
       public synchronized void run() { 
        PRGamePlayer player = new PRGamePlayer(client, game); 
       } 
      }; 
      new Thread(runnable).start(); 
     } 
    } catch (IOException io) { 
     MessageOutput.error("Server Connection Manager Failed...Shutting Down...", io); 
     // if the connection manager fails we want to closedown the server 
     System.exit(0); 
    } 
} 

然後在客戶端,我有這樣的事情..

public void connect(String ip) { 

     try { 
      comms = new Socket(ip, 12345); 
      comms.setTcpNoDelay(true); 
      // get the streams from the socket and wrap them round a ZIP Stream 
      // then wrap them around a reader and writer, as we are writing strings 
      this.input = new CompressedInputStream(comms.getInputStream()); 
      this.output = new CompressedOutputStream(comms.getOutputStream()); 
      this.connected = true; 
      startServerResponseThread(); 

     } catch (IOException e) { 
      ui.displayMessage("Unable to connect to server, please check and try again"); 
      this.connected = false; 
     } 

     if (connected) { 
      String name = ui.getUserInput("Please choose a player name"); 
      sendXML(XMLUtil.getXML(new NameSetAction(name, Server.VERSION))); 
     } 
    } 

    /** 
    * This method sets up the server response thread. The thread, sits patiently 
    * waiting for input from the server, in a seperate thread, so not to hold 
    * up any client side activities. When data is recieved from the server 
    * it is processed, to perform the appropriate action. 
    */ 
    public void startServerResponseThread() { 

     // create the runnable that will be used by the serverListenerThread, 
     // to listen for requests from the server 
     Runnable runnable = new Runnable() { 

     public void run() { 

      try { 
       // loop forever, or until the server closes the connection 
       while (true) { 

        processRequest(input.readCompressedString()); 
       } 
      } catch (SocketException sx) { 
       MessageOutput.error("Socket closed, user has shutdown the connection, or network has failed"); 
      } catch (IOException ex) { 
       MessageOutput.error(ex.getMessage(), ex); 
      } catch (Exception ex) { 
       MessageOutput.error(ex.getMessage(), ex); 
      } finally { 
       (PRClone.this).connected = false; 
       // only shutdown the server if the listener thread has not already been 
       // destroyed, otherwise the server will have already been shutdown 
       if (serverListenerThread != null) { 
        // shutdown the thread and inform the application the communications has closed 
        MessageOutput.debug("Shutting down server listener Thread"); 
       } 
      } 
     } 
     }; 

     // create the thread 
     serverListenerThread = new Thread(runnable); 
     // start the thread 
     serverListenerThread.start(); 

    } 

的客戶端能夠通過的OutputStream發送請求到服務器,讀取服務器來自輸入流的數據。

服務器可以接受來自客戶端的請求,並在GameController中處理它,也可以使用outputstream從服務器發送通知,同樣在GameController中。

編輯:另外,我應該注意到,我所有的通信都是通過XML完成的,客戶端或服務器上的控制器解碼XML並執行相關請求。

希望這會有所幫助。它確實爲我做了這項工作,並允許我的多人遊戲運作良好。

+0

我做的事情幾乎完全相同! :-) – Jonathan 2010-10-07 19:14:12

相關問題