Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ServerSocket-真的需要关闭它吗?_Java_Serversocket - Fatal编程技术网

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()
    方法(不调用
    close()
    -ing),则应用程序可能“抓取”该资源的所有可用实例,从而阻止其他应用程序获取实例

如果多次调用
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(…){…}
它有效地完成了相同的任务,只需很少的行。