2014-09-24 76 views
0

我正在創建一個多線程的聊天服務器,應該爲每個連接的客戶端創建一個單獨的線程。每次客戶端連接時,我的服務器都會創建一個客戶端處理程序類的新實例,該實例應該跟蹤來自/發往特定客戶端的進出消息。創建一個echo服務器 - 服務器只能響應一次

客戶端第一次連接到我的回顯服務器時,服務器將回應客戶端響應的迴應。但是,如果我嘗試再次向服務器發送消息,則客戶端會創建IOException。我自己創建了客戶端應用程序,但我知道它可行,因爲我可以很好地與其他服務器通信。我很確定問題出在這個客戶端處理程序類的運行方法的某個地方,但我無法弄清楚它爲什麼不起作用。下面是我的客戶端處理程序類的run方法:

public void run() { 
    try (
     BufferedReader in = 
       new BufferedReader(
        new InputStreamReader(clientSocket.getInputStream())); 

     PrintWriter out = 
      new PrintWriter(clientSocket.getOutputStream()); 
    ) { 
     long time = System.currentTimeMillis();   
     out.println("Server - " + time + ": " + in.readLine()); 

     out.close(); 

     try { 
      in.close(); 
     } catch (IOException e) { 
      System.err.println("Couldn't close input stream"); 
     } 
    } catch(IOException e) { 
     System.err.println("Got an IOException error while reading or writing from/to client"); 
    } 
} 

我猜我應該有某種while循環的地方,但我所有的努力來實現這個的都失敗了。例如。我試圖改變這種代碼:

long time = System.currentTimeMillis();   
out.println("Server - " + time + ": " + in.readLine()); 

要這樣:

String inputLine; 
while((inputLine = in.readLine()) != null) { 
    long time = System.currentTimeMillis();   
    out.println("Server - " + time + ": " + inputLine); 
} 

該解決方案是多還是少的甲骨文網站(http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html)怎麼說,它應該做的副本。

我認爲主要問題可能是我沒有真正掌握服務器/客戶端通信的整個概念,所以我們將非常感謝您向正確的方向發展。

提前致謝!

+0

我不是服務器方面的專家,但我認爲在客戶端處理程序類中存在某種「保持活動」循環。因此,如果客戶端連接並且第一次ping從客戶端發送到服務器,則會調用客戶端處理程序的運行方法。但是,在運行完第一次ping之後,接下來會發生什麼?該方法結束,線程停止,您的客戶端再也沒有遠端端點進行通信。例如,我的意思是,看看這個鏈接:http://wrapper.tanukisoftware.com/doc/german/app-hello-world-server.html - > HelloWorldServer.java有這行'while(true)'。你需要這個。 – Korashen 2014-09-24 07:56:48

+0

@Korashen問題出在服務器上而不是客戶端 - 示例中的服務器只能監聽單個客戶端連接 – 2014-09-24 08:19:58

+0

從OP的文章中我瞭解到,ClientHandler.class是服務器上的一個Runnable,將爲每個服務器立即執行連接的客戶端。正如我已經寫過的,在第一次握手之後,run()結束並且新創建的線程終止。這是我對帖子的理解,但我可能是錯的,不知道...... – Korashen 2014-09-24 08:38:10

回答

0

您提到的Oracle文章中的重要一點是標題爲 - 支持多客戶端的部分

基本的Java套接字API是一個阻塞API,它基本上意味着你調用一個方法,該方法阻塞,直到發生IO事件。如果您需要等待多個IO事件 - 對於您的情況,傳入的客戶端連接和傳入數據 - 您必須創建多個線程。

本文中顯示的服務器只接受單個傳入(客戶端)連接,並且在客戶端關閉後關閉,因爲服務器上的InputStream將返回null導致循環終止。

首先您的服務器需要看起來像這樣(這是簡化的例子):

try (ServerSocket serverSocket = new ServerSocket(portNumber)) 
{ 
    while (running) 
    { 
    Socket clientSocket = serverSocket.accept(); 
    new Thread(new ClientHandler(clientSocket)).start(); 
    } 
} 

注:開始爲每個客戶端連接線說明了這一點,但在管理的簡單化廣闊連接負載在服務器上。

客戶端代碼可以保持原樣。

正如我指出的那樣,基本知識將開發者手中的線程管理留給了開發人員 - 這經常會導致麻煩,因爲人們只是錯誤地認爲它是錯誤的。由於這個Java的套接字API已經被擴展來創建NIO API --Jakob Jenkov寫了一些很好的tutorials

它也值得看看Netty,我個人認爲它比NIO更容易使用。

+0

所以這意味着我的示例更改是正確的。我不明白爲什麼它不能在早些時候工作......如果我將示例更改中的代碼粘貼到我的程序中,那麼它現在運行得很好,這很煩人。謝謝! – 2014-09-24 09:13:38