2010-03-17 73 views
0

我嘗試玩插座了一下。爲此,我編寫了非常簡單的「客戶端」和「服務器」應用程序。爲什麼服務器死亡時套接字不會死掉?爲什麼當服務器還活着時,套接字就會死掉?

客戶:

import java.net.*; 

public class client { 
    public static void main(String[] args) throws Exception { 
    InetAddress localhost = InetAddress.getLocalHost(); 
    System.out.println("before"); 

    Socket clientSideSocket = null; 
    try { 
     clientSideSocket = new Socket(localhost,12345,localhost,54321); 
    } catch (ConnectException e) { 
     System.out.println("Connection Refused"); 
    } 
    System.out.println("after"); 

    if (clientSideSocket != null) { 
     clientSideSocket.close(); 
    } 
    } 
} 

服務器:

import java.net.*; 

public class server { 
    public static void main(String[] args) throws Exception { 
    ServerSocket listener = new ServerSocket(12345); 

    while (true) { 
     Socket serverSideSocket = listener.accept(); 
     System.out.println("A client-request is accepted."); 
    } 

    } 
} 

而且我發現我無法解釋一個問題:

  1. 我啓動服務器,比我開始一個客戶。連接成功建立(客戶端停止運行並且服務器正在運行)。然後關閉服務器並在一秒鐘內重新啓動。之後,我啓動一個客戶端,並寫入「連接拒絕」。在我看來,服務器「記住」舊連接,並不想打開第二個連接兩次。但我不明白如何可能。因爲我殺了以前的服務器,並開始一個新的!

  2. 我沒有立即啓動服務器後,前一個被殺死(我等待20秒)。在這種情況下,服務器將「忘記」以前服務器的套接字並接受來自客戶端的請求。

  3. 我啓動服務器,然後啓動客戶端。建立連接(服務器寫入:「客戶機請求被接受」)。然後我等一會兒,然後再次啓動客戶端。而服務器(它一直運行)再次接受請求!爲什麼?服務器不應該接受來自同一客戶端的請求 - IP和客戶端端口,但它確實!

回答

0

很可能操作系統還沒有關閉套接字,請嘗試netstat命令(應該可以在Windows或Unix/Linux上運行)。如果您在關閉客戶端或服務器後立即運行它,則仍然應該在「TIME_WAIT」「CLOSE_WAIT」或類似的地方使用套接字。您將無法重新使用這些端口,直到它們完全關閉。

0

每個問題3:許多客戶端可以連接到連接到單個端口的服務器。 Apache運行在80端口上,但這並不意味着只有一個人可以一次查看您的網站。在打開新套件之前,您還要關閉客戶端套接字。

+0

耶,我知道有很多客戶端可以連接到服務器扔在同一個服務器端口。但客戶端應該連接不同的客戶端IP和/或不同的客戶端端口。服務器無法接受來自同一客戶端的第二個連接 - IP和客戶端端口。是的,在我的情況下,我關閉客戶端的套接字,但服務器保持打開此套接字。所以,根據我的理解,服務器不應該允許使用已經佔用的客戶端IP端口號來打開新的套接字。 – Roman 2010-03-17 13:18:45

+0

您保持java Socket打開。操作系統將收到關於連接已關閉的信息,將它的內部句柄標記爲java套接字稱爲關閉的信息,並且將愉快地接受來自同一源端口的新連接,並在接受它時將該套接字綁定到新的Java套接字。您現有的非關閉Java套接字將不會再引用任何打開的套接字。 – nos 2010-03-17 13:23:34

+0

@nos,我保持從一側(服務器端)打開套接字,並從客戶端關閉。你是否說服務器會以某種方式注意到客戶端關閉了它的socket端,結果服務器將關閉他的socket端,並接受來自位於舊IP和舊端口上的客戶端的新請求? – Roman 2010-03-17 13:30:38

3
  1. 當您關閉服務器時,操作系統將保持套接字活動一段時間,以便它可以告訴客戶端連接已關閉。這涉及可能需要一些時間的超時和重傳。您可能會發現一些信息herehere。如果您希望服務器能夠立即重新綁定同一套接字,請調用setReuseAddress(true),儘管它可能是處於TIME_WAIT狀態的客戶端套接字。

  2. 該套接字不再處於TIME_WAIT狀態,並且可以被任何程序再次使用。

  3. 您的客戶端代碼只是連接,關閉套接字然後退出。就服務器/操作系統tcp堆棧而言,這些是不同的連接 - 只要任何先前的連接被拆除,重用源端口就可以了。 (請注意,在您撥打電話後,操作系統可能不會立即清除連接的所有內務。close()方法或程序退出,有涉及,因此可以確保一定的時間延遲的所有數據包已經發送/接收)

相關問題