2014-05-10 114 views
1

我是新來的主題。我試圖從服務器向客戶端廣播消息,但我不能。看起來服務器總是監聽一個新的連接。但我可以使用客戶端終端向其他客戶端發送消息。我的問題是如何在同時收聽的同時允許輸入。這是代碼。多線程聊天服務器

MultiThreadChatServerSync.java

import java.io.InputStreamReader; 
import java.io.DataInputStream; 
import java.io.PrintStream; 
import java.io.IOException; 
import java.net.Socket; 
import java.net.ServerSocket; 
import java.io.BufferedReader; 

public class MultiThreadChatServerSync extends Thread { 

    private static ServerSocket serverSocket = null; 
    private static Socket clientSocket = null; 
    private static Socket serversSocket = null; 
    private static DataInputStream iss = null; 
    private static PrintStream oss = null; 

    private static final int maxClientsCount = 10; 
    private static final clientThread[] threads = new clientThread[maxClientsCount]; 

    public static void main(String args[]) { 
     int num = 0; 
     int portNumber = 2222; 
     if (args.length < 1) { 
     System.out.println("Usage: java MultiThreadChatServerSync<portNumber> "Nowusingnumber=" + portNumber); 
     } else { 
     portNumber = Integer.valueOf(args[0]).intValue(); 
     } 
     try { 
     serverSocket = new ServerSocket(portNumber); 
     } catch (IOException e) { 
     System.out.println(e); 
     } 
     DataInputStream iss = null; 
     while (true) { 
     try { 
      System.out.println("5"); 

      num++; 

      // I want to be able to input text here to the server which will be 
      // send to different clients 
      // But I cannot 

      clientSocket = serverSocket.accept(); 
      int i = 0; 
      for (i = 0; i < maxClientsCount; i++) { 
       if (threads[i] == null) { 
        System.out.println("6"); 
        (threads[i] = new clientThread(clientSocket, threads)) 
         .start(); 
        break; 
       } 
      } 
      if (i == maxClientsCount) { 
       PrintStream os = new PrintStream(clientSocket.getOutputStream()); 
       os.println("Server too busy. Try later."); 
       os.close(); 
       clientSocket.close(); 
      } 
     } catch (IOException e) { 
      System.out.println(e); 
     } 
     } 

    } 
} 

class clientThread extends Thread { 

    private String clientName = null; 
    private DataInputStream is = null; 
    private PrintStream os = null; 
    private Socket clientSocket = null; 
    private final clientThread[] threads; 
    private int maxClientsCount; 

    public clientThread(Socket clientSocket, clientThread[] threads) { 
     this.clientSocket = clientSocket; 
     this.threads = threads; 
     maxClientsCount = threads.length; 
    } 

    public void run() { 
     int maxClientsCount = this.maxClientsCount; 
     clientThread[] threads = this.threads; 

     try { 

     is = new DataInputStream(clientSocket.getInputStream()); 
     os = new PrintStream(clientSocket.getOutputStream()); 
     String name; 
     while (true) { 
      os.println("Enter your name."); 
      name = is.readLine().trim(); 
      if (name.indexOf('@') == -1) { 
       break; 
      } else { 
       os.println("The name should not contain '@' character."); 
      } 
     } 

     os.println("Welcome " + name 
       + " to our chat room.\nTo leave enter /quit in a new line."); 
     synchronized (this) { 
      for (int i = 0; i < maxClientsCount; i++) { 
       if (threads[i] != null && threads[i] == this) { 
        clientName = "@" + name; 
        break; 
       } 
      } 
      for (int i = 0; i < maxClientsCount; i++) { 
       if (threads[i] != null && threads[i] != this) { 
        threads[i].os.println("*** A new user " + name 
         + " entered the chat room !!! ***"); 
       } 
      } 
     } 

     while (true) { 
      String line = is.readLine(); 
      if (line.startsWith("/quit")) { 
       break; 
      } 

      if (line.startsWith("@")) { 
       String[] words = line.split("\\s", 2); 
       if (words.length > 1 && words[1] != null) { 
        words[1] = words[1].trim(); 
        if (!words[1].isEmpty()) { 
        synchronized (this) { 
         for (int i = 0; i < maxClientsCount; i++) { 
          if (threads[i] != null && threads[i] != this 
           && threads[i].clientName != null 
           && threads[i].clientName.equals(words[0])) { 
           threads[i].os.println("<" + name + "> " 
            + words[1]); 

           this.os.println(">" + name + "> " + words[1]); 
           break; 
          } 
         } 
        } 
        } 
       } 
      } else { 

       synchronized (this) { 
        for (int i = 0; i < maxClientsCount; i++) { 
        if (threads[i] != null && threads[i].clientName != null) { 
         threads[i].os.println("<" + name + "> " + line); 
        } 
        } 
       } 
      } 
     } 
     synchronized (this) { 
      for (int i = 0; i < maxClientsCount; i++) { 
       if (threads[i] != null && threads[i] != this 
        && threads[i].clientName != null) { 
        threads[i].os.println("*** The user " + name 
         + " is leaving the chat room !!! ***"); 
       } 
      } 
     } 
     os.println("*** Bye " + name + " ***"); 

     synchronized (this) { 
      for (int i = 0; i < maxClientsCount; i++) { 
       if (threads[i] == this) { 
        threads[i] = null; 
       } 
      } 
     } 

     is.close(); 
     os.close(); 
     clientSocket.close(); 
     } catch (IOException e) { 
     } 
    } 
} 
+1

與修復任何錯誤一樣,它始於在編碼(間隔,命名,其他約定等)中具有良好標準。 – Rogue

+1

我推薦使用線程池執行程序 –

+0

@Rod_Algonquin:這是一個很好的建議 - 你應該增加更多的信息並使它成爲一個答案,以便我可以對它進行投票。 –

回答

4
  1. 你應該聽在後臺線程的客戶。你的代碼目前沒有這樣做,所以你的服務器實際上被鎖定在無盡的while (true)循環中。
  2. 你應該重構你的代碼,以便你的方法不是那麼大,笨拙。
  3. 你應該重構你的代碼,以便你的主要方法非常簡短,這樣它就可以讓手錶動起來,可以這麼說。
  4. 格式化您的代碼非常難以閱讀。請考慮編輯您的帖子並修復縮進樣式,使其一致和一致。我通常避免使用製表符縮進(論壇軟件通常不能很好地使用製表符)並縮進每個代碼塊4個空格。
  5. 你幾乎永遠不想讓你的類擴展線程。相反,讓它實現Runnable(或者使用Rod_Algonquin的優秀推薦)。
  6. 請勿使用已棄用的方法,如DataInputStream#readLine(...),因爲這可能會造成危險。

例如,你的主要可能是這樣簡單...

public static void main(String[] args) { 
    MyServer myServer = new MyServer(); 
    myServer.getThingsRunning(); 
} 

編輯
注意補充一個警告:我一般不工作使用套接字,服務器套接字或創建聊天程序,並且我仍然使用Executors的新功能,但是您可以沿着這些線構建代碼...

public class MultiServer implements Runnable { 
    public static final int PORT_NUMBER = 2222; 
    private static final int THREAD_POOL_COUNT = 20; 
    private List<MultiClient> clientList = new ArrayList<>(); 
    private ServerSocket serverSocket; 
    private ExecutorService clientExecutor = Executors.newFixedThreadPool(THREAD_POOL_COUNT); 

    public MultiServer() throws IOException { 
     serverSocket = new ServerSocket(PORT_NUMBER); 
    } 

    @Override 
    public void run() { 
     // embed your socket acceptance loop in a Runnable's run method 
     while (true) { 
     try { 
      Socket clientSocket = serverSocket.accept(); 
      MultiClient client = new MultiClient(clientSocket); 
      clientList.add(client); 
      clientExecutor.execute(client); 
     } catch (IOException e) { 
      // TODO notify someone of problem! 
      e.printStackTrace(); 
     } 
     } 
    } 

    // ..... more methods and such 

    public static void main(String[] args) { 
     try { 
     MultiServer multiServer = new MultiServer(); 
     new Thread(multiServer).start(); 
     } catch (IOException e) { 
     e.printStackTrace(); 
     } 

    } 
} 
+0

我認爲我的主要問題是,當聲明「clientSocket = serverSocket.accept();」正在執行我無法在終端上輸入任何內容。我想檢查一個新的客戶端,並能夠同時輸入。 – user2893681

+0

@ user2893681:請重新閱讀上面的第1點,因爲它只是爲了解決這個問題。再次,你的套接字監聽**並在後臺線程中接受**。 –

+0

我明白你的意思。但我將如何真正做到這一點。忍受我,我是新線程。 – user2893681