我尝试使用套接字。为此,我编写了非常简单的“客户端”和“服务器”应用程序。
客户端:
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.");
}
}
}
我发现了一个我无法解释的行为:
我启动服务器,而不是启动客户端。已成功建立连接(客户端停止运行且服务器正在运行)。然后我关闭服务器并在一秒钟内重新启动它。之后,我启动了一个客户端并写入“拒绝连接”。在我看来,服务器“记住”旧连接,并且不想两次打开第二个连接。但我不明白它是如何可能的。因为我杀死了以前的服务器并开始了一个新服务器!
我没有在前一个服务器被杀后立即启动服务器(我等了20秒)。在这种情况下,服务器“忘记”来自先前服务器的套接字并接受来自客户端的请求。
我启动服务器,然后启动客户端。建立连接(服务器写入:“接受客户端请求”)。然后我等一下再次启动客户端。服务器(一直运行)再次接受请求!为什么?服务器不应该接受来自同一客户端-IP和客户端端口的请求,但确实如此!
答案 0 :(得分:4)
当您关闭服务器时,操作系统会将套接字保持活动一段时间,以便它可以告诉客户端连接已关闭。这涉及超时和重传,这可能需要一些时间。您可能会找到一些信息here和here。如果您希望服务器能够立即重新绑定同一个套接字,请在其上调用setReuseAddress(true),尽管它可能是处于TIME_WAIT状态的客户端套接字。
套接字不再处于TIME_WAIT状态,任何程序都可以重复使用。
您的客户端代码只是连接,关闭套接字然后退出。就服务器/ OS tcp堆栈而言,这些是不同的连接 - 只要任何先前的连接被拆除,就可以重用源端口。 (请注意,在您调用.close()或程序退出后,操作系统可能不会立即拆除连接的所有内务处理,因此可能会有一些时间延迟,因此可以确保所有数据包都已发送/接收)
答案 1 :(得分:0)
操作系统可能尚未关闭套接字,请尝试使用netstat命令(应该在Windows或Unix / Linux上运行)。如果在关闭客户端或服务器后立即运行它,则仍应使用“TIME_WAIT”“CLOSE_WAIT”或类似的套接字。在完全关闭之前,您将无法重用这些端口。
答案 2 :(得分:0)
针对问题#3:许多客户端可以连接到连接到单个端口的服务器。 Apache在端口80上运行,但这并不意味着一次只能有一个人查看您的网站。您也在关闭客户端套接字之前打开一个新套接字。