2015-01-13 234 views
1

我有一個簡單的回聲服務器,我想當連接用戶輸入任何東西到服務器,所有其他客戶端和該客戶端將得到消息+「| MOD」。Java TCP Echo服務器 - 廣播

它現在不會發送給所有的客戶端,但它應該和我只是不知道我的代碼有什麼問題,所以現在它只會發送消息+「| MOD」給發送消息的客戶端,而不是所有其他人也應該如此。

我只是不明白,我有一個循環遍歷所有的客戶,但它仍然不會發送給所有。

SERVER:

package com.murplyx.server; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 

public class Server { 
    public static ServerSocket server; 
    public static ArrayList<Socket> clients = new ArrayList<Socket>(); 

    public static void broadcast(String message) { 
     try { 
      for (Socket socket : clients) { 
       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 

       out.println(message); 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String args[]) { 
     try { 
      server = new ServerSocket(9000); 

      while (true) { 
       clients.add(server.accept()); 

       for (Socket socket : clients) { 
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

        String line = in.readLine(); 

        if (line != null) { 
         broadcast(line + " | MOD"); 
        } 
       } 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

客戶:

package com.murplyx.client; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 

public class Client { 
    public static void main(String args[]) { 
     try { 
      while (true) { 
       Socket socket = new Socket("localhost", 9000); 

       BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 

       BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 

       out.println(input.readLine()); 

       System.out.println(in.readLine()); 

       socket.close(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

請幫助。

非常感謝。

+0

在'Server.broadcast()',你應該在每次迭代結束時用'out.close()'關閉'PrintWriter'。 – colti

+0

如果我沒有記錯,關閉PrintWriter將關閉底層套接字;如果您需要不止一次播放,我不會關閉它。 – Aify

回答

2

你有一個問題是每個客戶都會反覆做無限次的read stdin, write socket, read socket, write stdout, ...

當你廣播所有其他客戶端仍然通常坐在read stdin階段,所以他們不知道有什麼東西在等待在套接字上讀取。他們仍在等待用戶輸入內容。

最簡單的選擇之一是在每個客戶端啓動兩個線程 - 一個只處理read stdin, write socket, ...,另一個處理read socket, write stdout

[另一個(可能更復雜)選項我們在同一時間使用Java NIO的調查既插座和標準輸入可用輸入

第二個問題是,你在服務器中調用accept阻塞,然後從每個套接字依次讀取。您可能在一個線程中使用accept,並且每個客戶端都有另一個線程只從客戶端讀取,並重播給其他線程。 NIO也可以是一個很好的選擇 - 您可以輪詢讀取任何任何客戶端。

+0

Plus服務器在接受中掛起。 – Fildor

+0

@Fildor那也是 - 還沒有發現。 – Alnitak

+0

你可以請用代碼顯示嗎?在發佈我的問答後,我想,所有客戶端都具有相同的知識產權,因爲他們在測試他們時擁有相同的知識產權。 – super

0

我不能完全肯定的ArrayList如何與插座玩,所以我肯定會回去使用普通陣列爲它(看到這裏的編輯的代碼Java EchoTCPServer - Send to all clients

有些事情,我看到,我覺得能到被修復:

客戶端上:

- 停止關閉While循環中的套接字。在while循環外面關閉它(當客戶端完成服務器時)。另外,在Loop外部聲明套接字。

注意在這個:當客戶端套接字連接到服務器時,它會自動給出一個設備端口,因此兩個不同的設備將永遠不會有相同的IP連接到服務器。 TCP連接由2個端口,服務器套接字和客戶端套接字組成,套接字由[deviceip:port,serverip:port](iirc)表示。

- 另外,在客戶端,每次移動while循環時都不需要聲明新的讀取器。把這一切放在外面。 while循環中唯一的東西應該是你的readline + print語句。

-readLine是一種阻塞方法。 (以防萬一你不知道這意味着什麼,這意味着readLine會讓你的程序停留在那裏,直到它實際讀取一行爲止,爲了避免這種情況,你可以使用if語句和.ready()函數結合。功能檢查,看看是否有什麼要「讀」,因此,如果沒有輸入,它不會被上「的readLine」卡住

在服務器:

樣我前面說的,我會改回到使用正常的陣列

- 您的服務器仍然會卡住.accept()。因此,您將永遠不能讀取來自客戶端的輸入,除了在每次連接之後都進行一次輸入之外,您可以使用線程反而聽,它仍然會工作。

如:(此代碼去與那是在我附鏈接代碼(也是你的問題),把它放在你的服務器的while循環之前)

// create a tcp listener thread to deal with listening to clients 
Thread listenerThread = new Thread() { 
    public void run() { 
     String clientSentence; 

     while (true) { 
      //loop through each connected socket  
      for (int i = 0; i <= intLastSocket; i++) { 
       Socket z = clientSocket[i]; 
       //make sure the socket is not null or closed (can't do anything 
       //with closed or null sockets   
       if ((z != null) && (!z.isClosed())) { 
        try { 
         // Deal with TCP input here 
         BufferedReader input = new BufferedReader(new 
          InputStreamReader(z.getInputStream())); 
         // read in a line but only if there is one 
         if (input.ready()) { 
          clientSentence = input.readLine(); 
         } 
        } catch (IOException x) { 
         printTCP("IOException caught when reading in: " 
           + x.toString()); 
        } 
        if (clientSentence != null) { 
         System.out.println("Received from client: " 
           + clientSentence); 
         //send this message to the client 
         outputStream[i].println(clientSentence + " | MOD"); 
        } 

        // clear the input 
        clientSentence = null; 
       } 
      } 
     } 
    } 
}; 
listenerThread.start(); 
+0

與純數組相比,在使用'ArrayList <>'時存在_zero_交互。 – Alnitak

+0

@Alnitak你能詳細說明一下嗎? – Aify

+1

_「我不完全確定ArrayLists如何使用套接字播放」 - - 他們使用普通數組完全相同。 – Alnitak