为什么服务器死掉时套接字不会死掉?为什么当服务器处于活动状态时套接字会死亡?
我尝试玩一下套接字。为此,我编写了非常简单的“客户端”和“服务器”应用程序。
客户端:
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 和客户端端口的请求,但它确实接受了!
I try to play with sockets a bit. For that I wrote very simple "client" and "server" applications.
Client:
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();
}
}
}
Server:
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.");
}
}
}
And I found a behavior that I cannot explain:
I start a server, than I start a client. Connection is successfully established (client stops running and server is running). Then I close the server and start it again in a second. After that I start a client and it writes "Connection Refused". It seems to me that the server "remember" the old connection and does not want to open the second connection twice. But I do not understand how it is possible. Because I killed the previous server and started a new one!
I do not start the server immediately after the previous one was killed (I wait like 20 seconds). In this case the server "forget" the socket from the previous server and accepts the request from the client.
I start the server and then I start the client. Connection is established (server writes: "A client-request is accepted"). Then I wait a minute and start the client again. And server (which was running the whole time) accept the request again! Why? The server should not accept the request from the same client-IP and client-port but it does!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您关闭服务器时,操作系统将使套接字保持活动状态一段时间,以便它可以告诉客户端连接已关闭。这涉及超时和重传,这可能需要一些时间。您可能会在此处和此处。如果您希望服务器能够立即重新绑定同一个套接字,请调用 setReuseAddress(true) ,尽管它可能是处于 TIME_WAIT 状态的客户端套接字。
套接字不再处于 TIME_WAIT 状态,并且可以可以被任何程序再次重用。
您的客户端代码只是连接,关闭套接字,然后退出。就服务器/操作系统 tcp 堆栈而言,这些是不同的连接 - 只要任何先前的连接已被拆除,就可以重用源端口。 (请注意,在您调用 .close() 或程序退出后,操作系统可能不会立即拆除连接的所有内务处理,其中涉及一些时间延迟,因此可以确保所有数据包均已发送/接收)
When you close the server , the OS will keep the socket alive for a while so it can tell the client the connection has been closed. This involves timeouts and retransmissions which can take some time. You might find some info here and here. If you want your server to be able to immediately rebind the same socket, call setReuseAddress(true) on it, though it might be the client sockets that's in a TIME_WAIT state.
The socket is no longer in TIME_WAIT state, and can be reused again by any program.
Your client code just connects, closes the socket and then exits. As far as the server/OS tcp stack is concerned, these are different connections - it's fine to reuse the source port as long as any prior connection have been torn down. (Note that the OS might not tear down all of the housekeeping of the connection immediately after you call .close() or your program exits, there's some time delay involved so it can be sure all packets have been sent/received)
操作系统可能尚未关闭套接字,请尝试 netstat 命令(应该适用于 Windows 或 Unix/Linux)。如果在关闭客户端或服务器后立即运行它,则套接字仍应处于“TIME_WAIT”、“CLOSE_WAIT”或类似状态。在这些端口完全关闭之前,您将无法重复使用它们。
It is likely the operating system has not yet shutdown the sockets, try the netstat command (should work on Windows or Unix/Linux). If you run it immediately after you close client or server you should still the socket in "TIME_WAIT" "CLOSE_WAIT" or something similar. You wont be able to reuse those ports until they are fully closed.
根据问题 #3:许多客户端可以连接到连接到单个端口的服务器。 Apache 在端口 80 上运行,但这并不意味着一次只有一个人可以查看您的网站。此外,您在打开新客户端套接字之前要关闭客户端套接字。
Per Question #3: Many clients can connect to a server attached to a single port. Apache runs on port 80 but that doesn't mean only one person can view your website at a time. Also you are closing your client socket before you're opening a new one.