2016-11-17 69 views
0

當我運行我相當簡單的TCP服務器時,我注意到第一次嘗試連接併發送一個對象時出現連接重置錯誤。如果我保持服務器運行,但讓客戶端再次發送它一切正常。我在這裏虧本,這是什麼原因造成的?爲什麼我的連接在我嘗試寫入Socket時第一次復位?

客戶:

 for (int i = 0; i < 3; i++) { 
     Socket s = new Socket("192.168.0.10", 9750); 
     SysIO.print("Connected: " + s.isConnected()); 
     ObjectOutputStream oos = new ObjectOutputStream(
      new BufferedOutputStream(s.getOutputStream())); 
     Object obj = new OneMessage("Hi there: " + i); 
     oos.writeObject(obj); 
     oos.flush(); 

     sleep(1000); // <-- turns error on and off :/ 
    } 

服務器:

try (ServerSocket incomingSocket = new ServerSocket(mPort)) { 
     SysIO.print("Game Server started..."); 
     incomingSocket.setSoTimeout(mTimeout); 

     while (mRunning) { 
      Socket clientConnection = null; 
      try { 
       clientConnection = incomingSocket.accept(); 
       clientConnection.setSoTimeout(3000); 

       final Socket connection = clientConnection; 
       Thread requestHandlingThread = new Thread(() -> { 
        mRequestHandler.handleRequest(connection); 
       }); 
       requestHandlingThread.start(); 

      } catch (SocketTimeoutException ste) { 
       SysIO.print("TCP timeout..."); 
      } catch (IOException ex) { 
       Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } catch (BindException ex) { 
     SysIO.print("Could not bind: " + ex.getMessage()); 
    } catch (IOException ex) { 
     SysIO.print("There was a problem with IO in TCP Server: " + ex.getMessage()); 
     Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex); 
    } 

請求處理程序:

public void handleRequest(Socket aRequest) { 

    try { 
     SysIO.print("Connected: " + aRequest.isConnected()); 
     ObjectInputStream ois = new ObjectInputStream(
      new BufferedInputStream(aRequest.getInputStream())); 
     GameMessage message = (GameMessage) ois.readObject(); 

     aRequest.close(); 


     SysIO.print("Received: " + message.getType()); 
    } catch (IOException | ClassNotFoundException ex) { 
     SysIO.print("IO exception: " + ex.getMessage()); 
     Logger.getLogger(SimpleHandler.class.getName()).log(Level.SEVERE, null, ex); 
    } 

} 

我試着關閉和從服務器的每個請求後未關閉套接字。

如果我運行客戶端沒有循環它似乎工作,我認爲它在第一次失敗,但我不能重新創建它。

如果我嘗試在循環中運行客戶端,所有連接將在第一次運行客戶端時失敗,但如果我重新啓動客戶端,則所有連接都將成功。

讓睡眠(1000)暫停上述循環將使所有連接成功。這很簡單,服務器無法處理快速連接嘗試?我希望把請求處理放在單獨的線程中可以實現這一點。但爲什麼循環中的第一個連接也會失敗?

問候, 基督教

+1

對於讀取超時,三秒鐘是相當短的。至少應該有十個。您需要在循環結束時在客戶端中使用'oos.close()'。 – EJP

+0

NB'isConnected()'在你測試的時候不可能是假的。 – EJP

回答

0

所以最後我eneded了這樣的事情:

客戶:

try { 
    Socket connection = new Socket(mHostAddress, mHostPort); 
    connection.setSoTimeout(mTimeOut); 
    ObjectOutputStream outgoing = new ObjectOutputStream(
      new BufferedOutputStream(connection.getOutputStream() 
      )); // <-- Opening output stream first in client (opposite to server) 
    outgoing.writeObject(mMessage); 
    outgoing.flush(); 
    outgoing.close(); // <-- closing the stream as per EJP's comment 
} catch (IOException ex) { 
    System.out.print("IOException in TCPSender: " + ex.getMessage()); 
} 

服務器:

ExecutorService pool = Executors.newFixedThreadPool(mClientThreads); 
try (ServerSocket server = new ServerSocket(mPort)) { 
    while (mRunning) { 
     final Socket client = server.accept(); 
     client.setSoTimeout(mTimeOut); 
     pool.execute(() -> { 
      mMessageHandler.handle(client); // mMessageHandler = NetworkMessageHandler 
     }); 
    } 
} catch (IOException ex) { 
    System.out.println("IO Exception occurred in TCPServer: " 
      + ex.getMessage()); 
} finally { 
    System.out.println("Server stopped..."); 
} 

NetworkMessageHandler

try { 
    ObjectInputStream input = new ObjectInputStream(
      new BufferedInputStream(aClient.getInputStream()) // Input first in server 
    ); 
    NetworkMessage message = (NetworkMessage) input.readObject(); 
    input.close(); // <-- closing stream 
    aClient.close(); // <-- making sure to close the Socket connection to client 

    act(message, sendersIP); <-- acting on the message from client 

} catch (IOException ex) { 
    System.out.println("An IO exception occurred " 
      + "in NetworkMessageHandler: " + ex.getMessage()); 
} catch (ClassNotFoundException ex) { 
    System.out.println("Could not recreate the sent class: " 
      + ex.getMessage()); 
} 

我確信我不會錯過關閉我的流和套接字,並且遵循this oracle tutorial的某些提示提示。

Regards, Christian

+0

您需要首先在*至少一個對等端創建ObjectOutputStream。最好是兩個,所以一個同伴不依賴於另一個。沒有理由在兩端採取相反的方式,它只是帶來了不必要的風險。 – EJP

相關問題