2012-10-29 72 views
15

因此,現在我正在製作基於客戶端服務器的應用程序多線程。在服務器端,我創建了一個可以接受的單一連接的線程。向所有客戶端發送消息(客戶端 - 服務器通信)

在線程類中,我製作了一個將命令發送給客戶端的方法。我只想要的是,如何向所有正在運行的客戶端發送參數?對於簡單的陳述,我只是想讓這臺服務器向所有連接的客戶端發送消息。

我已閱讀this post並從this link找到sendToAll(String message)方法。但是當我嘗試使用我的代碼時,在ServerSocket中沒有類似的方法。

好吧,這是我的服務器和線程的示例代碼。

class ServerOne{ 

ServerSocket server = null; 
... 

ServerOne(int port){ 
      System.out.println("Starting server on port "+port); 
    try{ 
     server = new ServerSocket(port); 
       System.out.println("Server started successfully and now waiting for client"); 

    } catch (IOException e) { 
     System.out.println("Could not listen on port "+port); 
     System.exit(-1); 
    } 
} 

public void listenSocket(){ 
    while(true){ 
     ClientWorker w; 
     try{ 
      w = new ClientWorker(server.accept()); 
      Thread t = new Thread(w); 
      t.start(); 
     } catch (IOException e) { 
      System.out.println("Accept failed: 4444"); 
      System.exit(-1); 
     } 
    } 
} 

protected void finalize(){ 
    try{ 
     server.close(); 
    } catch (IOException e) { 
     System.out.println("Could not close socket"); 
     System.exit(-1); 
    } 
} 
} 

class ClientWorker implements Runnable{ 
Socket client; 

ClientWorker(Socket client){ 
    this.client = client; 
} 
public void run(){ 
    ... 
     sendCommand(parameter); 
    ... 
} 

public void sendCommand(String command){ 
    PrintWriter out = null; 
    try { 
     out = new PrintWriter(client.getOutputStream(), true); 
     out.println(command); 
    } catch (IOException ex) {} 
} 

} 

感謝您的幫助:)

回答

19

下面的答案,不建議完全成熟的服務器,作爲這個你應該使用Java EE使用servlet,Web服務等

這僅其中幾臺電腦要連接以執行特定任務,並且使用簡單的Java套接字不是一個普遍問題。想想分佈式計算或多人遊戲。

編輯:我 - 因爲第一篇文章 - 大大更新了這個架構,現在測試,線程安全的。任何需要它的人都可以下載它here

只需使用(直接或通過繼承)ServerClientstart()他們,一切準備就緒。閱讀內聯評論以獲取更多強大的選項。


雖然客戶之間的溝通相當複雜,但我會盡量簡化它,這是最可能的。

這裏是點,在服務器:

  • 保持連接的客戶端列表。
  • 定義一個線程,用於服務器輸入。
  • 定義接收到的消息隊列。
  • 線程從隊列中輪詢,並使用它。
  • 發送消息的一些實用方法。

以及客戶端:

  • 定義一個線程,用於客戶端輸入。
  • 定義接收到的消息隊列。
  • 線程從隊列中輪詢,並使用它。

這裏的服務器類:

public class Server { 
    private ArrayList<ConnectionToClient> clientList; 
    private LinkedBlockingQueue<Object> messages; 
    private ServerSocket serverSocket; 

    public Server(int port) { 
     clientList = new ArrayList<ConnectionToClient>(); 
     messages = new LinkedBlockingQueue<Object>(); 
     serverSocket = new ServerSocket(port); 

     Thread accept = new Thread() { 
      public void run(){ 
       while(true){ 
        try{ 
         Socket s = serverSocket.accept(); 
         clientList.add(new ConnectionToClient(s)); 
        } 
        catch(IOException e){ e.printStackTrace(); } 
       } 
      } 
     }; 

     accept.setDaemon(true); 
     accept.start(); 

     Thread messageHandling = new Thread() { 
      public void run(){ 
       while(true){ 
        try{ 
         Object message = messages.take(); 
         // Do some handling here... 
         System.out.println("Message Received: " + message); 
        } 
        catch(InterruptedException e){ } 
       } 
      } 
     }; 

     messageHandling.setDaemon(true); 
     messageHandling.start(); 
    } 

    private class ConnectionToClient { 
     ObjectInputStream in; 
     ObjectOutputStream out; 
     Socket socket; 

     ConnectionToClient(Socket socket) throws IOException { 
      this.socket = socket; 
      in = new ObjectInputStream(socket.getInputStream()); 
      out = new ObjectOutputStream(socket.getOutputStream()); 

      Thread read = new Thread(){ 
       public void run(){ 
        while(true){ 
         try{ 
          Object obj = in.readObject(); 
          messages.put(obj); 
         } 
         catch(IOException e){ e.printStackTrace(); } 
        } 
       } 
      }; 

      read.setDaemon(true); // terminate when main ends 
      read.start(); 
     } 

     public void write(Object obj) { 
      try{ 
       out.writeObject(obj); 
      } 
      catch(IOException e){ e.printStackTrace(); } 
     } 
    } 

    public void sendToOne(int index, Object message)throws IndexOutOfBoundsException { 
     clientList.get(index).write(message); 
    } 

    public void sendToAll(Object message){ 
     for(ConnectionToClient client : clientList) 
      client.write(message); 
    } 

} 

這裏的客戶端類:

public class Client { 
    private ConnectionToServer server; 
    private LinkedBlockingQueue<Object> messages; 
    private Socket socket; 

    public Client(String IPAddress, int port) throws IOException{ 
     socket = new Socket(IPAddress, port); 
     messages = new LinkedBlokingQueue<Object>(); 
     server = new ConnecionToServer(socket); 

     Thread messageHandling = new Thread() { 
      public void run(){ 
       while(true){ 
        try{ 
         Object message = messages.take(); 
         // Do some handling here... 
         System.out.println("Message Received: " + message); 
        } 
        catch(InterruptedException e){ } 
       } 
      } 
     }; 

     messageHandling.setDaemon(true); 
     messageHandling.start(); 
    } 

    private class ConnectionToServer { 
     ObjectInputStream in; 
     ObjectOutputStream out; 
     Socket socket; 

     ConnectionToServer(Socket socket) throws IOException { 
      this.socket = socket; 
      in = new ObjectInputStream(socket.getInputStream()); 
      out = new ObjectOutputStream(socket.getOutputStream()); 

      Thread read = new Thread(){ 
       public void run(){ 
        while(true){ 
         try{ 
          Object obj = in.readObject(); 
          messages.put(obj); 
         } 
         catch(IOException e){ e.printStackTrace(); } 
        } 
       } 
      }; 

      read.setDaemon(true); 
      read.start(); 
     } 

     private void write(Object obj) { 
      try{ 
       out.writeObject(obj); 
      } 
      catch(IOException e){ e.printStackTrace(); } 
     } 


    } 

    public void send(Object obj) { 
     server.write(obj); 
    } 
} 
+0

你的答案是偉大的,但你缺乏一些冒號和你應該改變'messages.dequeue();'和'messages.enqueue();''來messages.take();'和' messages.put();' – Danon

+1

另外,你確定這個類是線程安全的嗎?我的意思是,如果在accept/threads更改clientList時調用sendToOne()/ sendToAll會怎樣? – Danon

+0

@Danon請參閱編輯。 – Mordechai

3

有一個在服務器套接字沒有方法將數據或消息發送給所有正在運行的客戶爲例線程。 請通過ServerThread.java程序調用sendToAll usng服務器。

// ... and have the server send it to all clients 
server.sendToAll(message); 
2

退房zeroMQ。有一些方法稱爲「pub sub」或「發佈訂閱」,它們會按照您的意願進行操作。你也可以用它在你的線程之間進行通信。我認爲這是一個了不起的圖書館。它擁有java或jzmq綁定以及超過30多個其他應用程序,因此您應該可以在程序中使用它。

http://www.zeromq.org/

相關問題