2014-01-15 116 views
1

現在我正在與客戶端 - 服務器應用程序進行一些小規模的工作,例如通過java應用程序與運行服務器應用程序的樹莓派進行通信。Java ServerSocket只接受2個連接

那麼,我發現了一個問題,我沒有找到一個可能的解決方案。使用下面的代碼,我可以連接兩次到服務器,但2次連接後它不會再接受任何連接。例如,我第一次啓動客戶端,它可以很好地工作。然後我關閉客戶端並重新啓動它並再次運行。但是如果我關閉它並且第三次啓動它,它就什麼都不會做。服務器不會接受連接。我在我的私人網絡中使用不同的個人電腦進行了嘗試,但從未獲得第三個連接。

這裏是我的服務器上運行的代碼:

public class Receiver { 

private final Logger logger = Logger.getLogger(this.getClass().getName()); 

private ServerSocket serverSocket; 
private boolean isRunning; 

public Receiver(int port) { 
    isRunning = true; 
    try { 
     serverSocket = new ServerSocket(port); 
     logger.log(Level.FINER, "start listening at port " + port); 
     logger.log(Level.FINER, "established successful."); 
    } catch (IOException e) { 
     logger.log(Level.SEVERE, "Error while opening socket:\n" + LogUtil.getStackTrace(e)); 
     System.exit(1); 
    } 
} 

/** 
* server starts to listen at the specific port 
*/ 
public void listenServer() { 
    logger.log(Level.FINER, "Server is listening"); 

    while (isRunning) { 
     try { 
      final Socket clientsocket = serverSocket.accept(); 
      logger.log(Level.FINER, "Server accepted Connection from " + clientsocket.getInetAddress()); 
      new Thread(new Runnable() { 

       @Override 
       public void run() { 
        handleConnection(clientsocket); 
       } 
      }).start(); 
     } catch (IOException e) { 
      logger.log(Level.SEVERE, "Connection with Client failed."); 
     } 
    } 
} 

/** 
* handles the given connection 
* 
* @param clientSocket 
*   the given client socket for this connection 
*/ 
private void handleConnection(Socket clientSocket) { 

    ObjectInputStream instream = null; 
    ObjectOutputStream outstream = null; 

    try { 
     outstream = new ObjectOutputStream(clientSocket.getOutputStream()); 
     instream = new ObjectInputStream(clientSocket.getInputStream()); 
     final RequestProcessor processor = new RequestProcessor(); 
     final InetAddress inetAdress = clientSocket.getInetAddress(); 

     logger.log(Level.FINER, "handle connection from " + inetAdress); 

     Object inob; 
     while ((inob = instream.readObject()) != null) { 
      logger.log(Level.FINER, "received Object from " + inetAdress); 
      final ObjectOutputStream finalOutputStream = outstream; 
      final Object finalInob = inob; 

      new Thread() { 
       public void run() { 
        setPriority(MAX_PRIORITY); 
        Object outob; 
        try { 
         outob = processor.processObject(finalInob); 
         logger.log(Level.FINER, "send Respond to: " + inetAdress + " Error: " + (outob instanceof ErrorMessage)); 
         finalOutputStream.writeObject(outob); 
         finalOutputStream.flush(); 
        } catch (IOException e) { 
         logger.log(Level.SEVERE, "Connection closed to " + inetAdress); 
        } 
       } 
      }.start(); 
     } 

     closeConnection(clientSocket, instream, outstream); 
    } catch (IOException e) { 
     logger.log(Level.SEVERE, "Connection closed to " + clientSocket.getInetAddress()); 
    } catch (ClassNotFoundException e) { 
     logger.log(Level.SEVERE, "Connection closed to " + clientSocket.getInetAddress()); 
    } finally { 
     closeConnection(clientSocket, instream, outstream); 
    } 

} 

/** 
* closes InputStream, OutputStream and socket 
* 
* @param socket 
* @param instream 
* @param outstream 
*/ 
private void closeConnection(Socket socket, InputStream instream, OutputStream outstream) { 
    this.isRunning = false; 
    if (instream != null) { 
     try { 
      instream.close(); 
     } catch (IOException e) { 
     } 
    } 
    if (outstream != null) { 
     try { 
      outstream.close(); 
     } catch (IOException e) { 
     } 
    } 
    if (socket != null) { 
     try { 
      socket.close(); 
     } catch (IOException e) { 
     } 
    } 
    logger.log(Level.FINER, "Connection was closed to client " + socket.getInetAddress()); 
} 

/** 
* closes all connections and ends the server 
*/ 
public void endAllConnections() { 
    this.isRunning = false; 

    if (this.serverSocket != null) 
     try { 
      this.serverSocket.close(); 
     } catch (IOException e) { 
      // do nothing 
     } 
     } 
    } 

這裏是我用來連接到該服務器的客戶端代碼:

public class SocketConnector implements IConnector { 

    private final Logger logger = Logger.getLogger(this.getClass().getName()); 

    private Socket s; 
    private ObjectOutputStream oos; 
    private ObjectInputStream ois; 

    /** 
    * creates a new connection 
    * 
    * @param host 
    *   given host 
    * @param port 
    *   given port 
    * 
    * @throws UnknownHostException 
    * @throws IOException 
    */ 
    public SocketConnector(String host, int port) throws UnknownHostException, IOException { 
     logger.log(Level.FINER, "Establish connection to " + host + ":" + port); 
     s = new Socket(host, port); 
     oos = new ObjectOutputStream(s.getOutputStream()); 
     ois = new ObjectInputStream(s.getInputStream()); 
    } 

     // some methos which use oos and ois. 

是否有人也許知道爲什麼當2個客戶端連接並斷開連接時,服務器不會再接受任何連接?我GOOGLE了很多,但沒有找到一個合適的答案:/ 服務器日誌說,它甚至不接受新的連接。

感謝提前:)

+0

你在Windows中運行嗎?因爲我認爲每個主機有2個連接的TCP/IP堆棧限制,您可以通過與Windows註冊表(或使用其他主機名稱,如IP地址和主機名)混合來調整 –

+0

此代碼還有其他問題。 1.對象流應該在run()方法中創建,而不是在構造函數中創建:否則它們將在accept()線程中執行,可能會阻塞它。 2.除非您寫入null,否則ObjectInputStream不會返回null,因此在不返回null的情況下循環無效。它在流結束時拋出EOFException:捕獲該錯誤,並在獲取時拋棄。 @JasonSperske有一個TCP積壓限制,但它比2高得多。 – EJP

+0

謝謝。 Vutran解決了主要問題。我會再看看它,按照您的建議,使其更清潔EJP :) – chf

回答

2

的情況是:
調用final Socket clientsocket = serverSocket.accept();第一次,當 ,它等待第一個客戶。當第一個客戶端連接時,您將此客戶端傳遞給線程,然後繼續第二次調用final Socket clientsocket = serverSocket.accept();的循環。由於開始一個線程比進入下一個循環需要更多的時間,因此isRunning仍然是true。在handleConnection(Socket clientSocket)中,您可以撥打closeConnection(clientSocket, instream, outstream);,將isRunning設置爲false。這就是我想說的。當第二個客戶端連接時,您也將此客戶端傳遞給另一個線程,然後繼續isRunningfalse的循環,因此循環終止。因此,你無法到達第三個客戶。

+0

謝謝:)這就是問題所在。恥辱我沒有看到:/真的沒有看到我把它設置爲假^^ – chf