2012-10-27 128 views
2

我目前參與了一個項目,在我們正在建立一個通信系統在學校使用Android手機。爲此,我們將使用一臺服務器,它可以向所有客戶端打開套接字,從而實現通信。ServerSocket沒有接受監聽()

我已經完成了幾個聊天應用程序,沒有任何套接字或線程處理問題,但這次出於某種原因,它讓我浮想聯翩。

的問題是,應用程序啓動時,只要我開始ServerSocket對象,serverSocket = new ServerSocket(5000)聽,而不是在serverSocket.accept()

這是爲什麼?

當我使用下面的方法:

public void startListen(String port) { 
try { 
    serverSocket = new ServerSocket(Integer.parseInt(port)); 
    portField.setEditable(false); 
} catch (IOException e) { 
    printMessage("Failed to initiate serverSocket: " + e.toString()); 
}} 

端口被顯示爲(使用netstat)在命令提示聽力。如果我不叫它,端口不會被列爲收聽。

TCP 0.0.0.0:5000計算機:0 LISTENING

所以,這裏是什麼我使用ServerSocket對象時失蹤?使用ServerSocket的舊程序在我撥打accept()之前不會開始收聽。

+1

我們中的一些人表現得更好,@StephenC,當我們明白了爲什麼一些工作。有些人認爲這會讓他們在他們的領域更有價值,因爲他們實際上可以向其他人解釋這些知識,並將這種概念知識傳播給其他技術。 – jmort253

+0

你錯了。所有使用ServerSocket的較舊程序在構建或綁定它時立即開始監聽。進入'聽'狀態與接受()無關。不是一個真正的問題。 – EJP

回答

7

如果你正在談論Java ServerSocket,那麼它沒有listen方法,大概是因爲它不同於客戶端套接字。在這種情況下,一旦它有一個端口號(在構造函數中或作爲bind的一部分),它就可以繼續並自動偵聽。

原因「常規」插口(一拉BSD)有聽的,因爲同類型的用於客戶端服務器,所以你需要自己決定你將如何使用它。這不是與ServerSocket的情況下,因爲,嗯,這是一個服務器插座:-)

說實話,我不知道爲什麼你會在乎聆聽是否是活躍accept被調用之前。這是「監聽」呼叫(這是該類中隱含的),應該將服務器標記爲業務開放。此時,通信層應該開始允許傳入呼叫排隊等待您撥打accept。這通常是他們工作的方式,排隊請求以防您的程序在接受它們時有點緩慢。


而言,爲什麼它做它,它實際上應該根據源代碼。在OpenJDK6 source/share/classes/java/net/ServerSocket.java,建設者都最終調用一個構造函數:

public ServerSocket(int port, int backlog, InetAddress bindAddr) 
throws IOException { 
    setImpl(); 
    if (port < 0 || port > 0xFFFF) 
     throw new IllegalArgumentException(
        "Port value out of range: " + port); 
    if (backlog < 1) 
     backlog = 50; 
    try { 
     bind(new InetSocketAddress(bindAddr, port), backlog); 
    } catch(SecurityException e) { 
     close(); 
     throw e; 
    } catch(IOException e) { 
     close(); 
     throw e; 
    } 
} 

這調用bind(同一個文件)如下:

public void bind(SocketAddress endpoint, int backlog) throws IOException { 
    if (isClosed()) 
     throw new SocketException("Socket is closed"); 
    if (!oldImpl && isBound()) 
     throw new SocketException("Already bound"); 
    if (endpoint == null) 
     endpoint = new InetSocketAddress(0); 
    if (!(endpoint instanceof InetSocketAddress)) 
     throw new IllegalArgumentException("Unsupported address type"); 
    InetSocketAddress epoint = (InetSocketAddress) endpoint; 
    if (epoint.isUnresolved()) 
     throw new SocketException("Unresolved address"); 
    if (backlog < 1) 
     backlog = 50; 
    try { 
     SecurityManager security = System.getSecurityManager(); 
     if (security != null) 
      security.checkListen(epoint.getPort()); 
     getImpl().bind(epoint.getAddress(), epoint.getPort()); 
     getImpl().listen(backlog); 
     bound = true; 
    } catch(SecurityException e) { 
     bound = false; 
     throw e; 
    } catch(IOException e) { 
     bound = false; 
     throw e; 
    } 
} 

相關位有:

getImpl().bind(epoint.getAddress(), epoint.getPort()); 
getImpl().listen(backlog); 

這意味着bindlisten都是在較低級別完成,當你創建套接字。

因此問題是沒有這麼多「爲什麼會突然出現在netstat?」但是「爲什麼不出現在netstat之前?」

我可能快放下一個誤讀你的一部分,或者不那麼好實現的netstat。前者更可能,除非你專門測試了一個你沒有調用accept的套接字,這是不太可能的。

2

我想你的accept目的輕微錯誤的想法。將一個ServerSocket隊列和隊列accept對一個阻塞出隊操作。的插座,一旦被綁定到一個端口和accept方法按照自己的速度從隊列他們入隊的傳入連接。所以是的,他們可以更好地命名爲accept,這樣更容易混淆。