Java ServerSocket-真的需要关闭它吗?
我有一个该死的结构:Java ServerSocket-真的需要关闭它吗?,java,serversocket,Java,Serversocket,我有一个该死的结构: public void run() { try { if (!portField.getText().equals("")) { String p = portField.getText(); CharSequence numbers = "0123456789"; btnRun.setEnabled(false);
public void run() {
try {
if (!portField.getText().equals("")) {
String p = portField.getText();
CharSequence numbers = "0123456789";
btnRun.setEnabled(false);
if (p.contains(numbers)) {
ServerSocket listener = new ServerSocket(Integer.parseInt(p));
while (true) {
Socket socket = listener.accept();
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("Hi there, human.");
} finally {
socket.close();
}
}} else {
JOptionPane.showMessageDialog(null, "Only numbers are allowed.");
}
}
} catch (NumberFormatException | HeadlessException | IOException e) {
e.printStackTrace();
}
}
正如您所看到的,我需要完全像关闭套接字一样关闭侦听器。问题是,如果我在循环之后尝试这样做,代码将“不可访问”,如果我尝试在ServerSocket的任何位置声明一个字段,我会得到一个NullPointerException。我不想关闭ServerSocket和socket/客户端,因为我想建立新的连接
这就是我的问题:
在这种情况下,真的有必要关闭ServerSocket吗?当软件关闭时,ServerSocket会自动关闭吗?(系统出口(0))。如果在我关闭软件时ServerSocket继续运行只是因为我没有关闭它,那么我就有问题了,因为我无法找到那该死的代码来关闭它:)。是的。虽然销毁对套接字的引用可能会导致垃圾收集器完成它,但这并没有指定它将被关闭。在许多情况下,这是特定于实现的,有时会由于性能问题,甚至是难以跟踪的微小缺陷而与设计脱轨 将引用保留在任何位置都是一个肯定的赌注,即使使用weakreference,它也不会这样做 现在操作系统提供的套接字数量有限(由于其设计)。当您打开越来越多的套接字时,操作系统会承受压力,最终会耗尽套接字,从而导致Java或其他程序失败。此外,根据您或默认设置的套接字选项,此套接字可能会发送keepalives,从而耗尽其他端点上的资源 退出时,套接字在其构造函数中注册关闭操作以关闭它和/或操作系统的自动清理来关闭它
永远不要依赖OS/JVM行为或终结来关闭套接字,尤其是如果您有多个套接字,即使您不打算同时使用所有套接字。是的,有必要释放任何有限的资源,因为否则,你的应用程序将使主机上的其他进程缺乏资源,无法长期维持 我是这样做的:
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = ... // init here
} catch (...) {
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// log error just in case
}
}
}
}
另外,将GUI代码移动到另一个类是一个好主意,以保持干净。一个答案是您确实应该
close()
resources。。。即使这不是绝对必要的
为什么?
因为,(假设)意味着它不是严格必要的情况可能会改变强>
而且。。。让我们面对现实吧。。。编写自动关闭服务器套接字的代码很容易
但请继续阅读
在这种情况下,真的有必要关闭ServerSocket吗 视情况而定
- 如果您确定
只运行一次,然后应用程序总是会完全关闭(下面的模警告),那么不关闭run()
不会造成任何实际伤害ServerSocket
- 否则,未能关闭()可能会造成伤害
- 服务器套接字可以在端口上持有“锁”,防止应用程序的另一个实例侦听该端口(取决于操作系统)
- 服务器套接字可能是有限的资源,如果多次调用
方法(不调用run()
-ing),则应用程序可能“抓取”该资源的所有可用实例,从而阻止其他应用程序获取实例close()
run()
当软件关闭时,ServerSocket会自动关闭吗
ServerSocket不会“自行关闭”,除非它被垃圾收集并完成。你不能指望JVM退出时会发生这两种情况。但从更广泛的意义上讲,当JVM退出时,底层服务器套接字资源通常会自动关闭(释放)
但完整的答案实际上取决于“软件关闭”的含义,也取决于平台的性质。例如:
- 如果shutdown意味着JVM完全退出,并且“拥有”底层服务器套接字(从操作系统的角度来看)的相应进程也退出,那么操作系统将关闭该套接字。。。至少在现代Unix/Linux/Windows平台上。(请注意,Android是Linux的幕后黑手)
- 如果“软件”类似于在web容器中运行的webapp,“关闭”可能意味着与JVM退出不同的内容,并且ServerSocket可能在关闭后继续存在(而不是关闭)
如果JVM嵌入到其他的(例如在大型C/C++应用程序中),并且其他东西不退出,那么OS就不知道释放底层服务器套接字。
- 如果您运行的平台上的操作系统不提供与Unix/Linux/(现代)Windows上相同级别的进程分离/资源管理,则在进程退出时操作系统可能不会关闭底层服务器套接字。(此场景可能适用于嵌入式系统上的Java实现…)
无论如何,做正确的事情并不难。在Java 7及更高版本中:
public void run() {
String p = portField.getText().trim();
if (p.isEmpty()) {
return;
}
btnRun.setEnabled(false);
try (ServerSocket listener = new ServerSocket(Integer.parseInt(p))) {
while (true) {
try (Socket socket = listener.accept();
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true)) {
out.println("Hi there, human.");
}
}
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Only numbers are allowed.");
} catch (HeadlessException | IOException e) {
e.printStackTrace();
} finally {
btnRun.setEnabled(true); // ... possibly
}
}
(虽然,我看不到捕捉HeadlessException
的意义,它似乎是从按钮侦听器调用的操作。)一句话,是的。我建议在这里使用Java 7代码,特别是使用资源进行尝试:try(ServerSocket ServerSocket=…){…}catch(…){…}
它有效地完成了相同的任务,只需很少的行。