java ServerSocket - 真的有必要关闭()吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17385452/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 01:49:52  来源:igfitidea点击:

ServerSocket - Is it really necessary to close() it?

javaserversocket

提问by Ericson Willians

I have this damnable structure:

我有这个该死的结构:

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();
        } 
    }

As you can see, I need to close the listener exactly as I did with the socket. The problem is that if I try to do so after the loop the code will be "unreachable", and if I try to declare a field anywhere for the ServerSocket, I get a NullPointerException. I don't want to close the ServerSocket together with the socket/client because I want to make new connections.

正如您所看到的,我需要完全像关闭套接字一样关闭侦听器。问题是,如果我在循环之后尝试这样做,代码将“无法访问”,并且如果我尝试在任何地方为 ServerSocket 声明一个字段,我会收到 NullPointerException。我不想将 ServerSocket 与套接字/客户端一起关闭,因为我想建立新的连接。

So that's my question:

所以这就是我的问题:

It's REALLY necessary to close the ServerSocket in this case? The ServerSocket closes itself by its own when the software is shut down? (System.exit(0)). If the ServerSocket continues to run when I close the software just because I have not closed it, then I have a problem, because I can't reach that bloody piece of code to close it :).

在这种情况下真的有必要关闭 ServerSocket 吗?ServerSocket在软件关闭时自行关闭?(System.exit(0))。如果 ServerSocket 在我关闭软件时继续运行只是因为我没有关闭它,那么我有问题,因为我无法访问那段该死的代码来关闭它:)。

采纳答案by nanofarad

Yes. While destroying references to the socket maycause the garbage collector to finalize it, that does not specify that it will be closed. This is implementation-specific in many cases, and can sometimes derail relative to design due to performance or even minute bugs that are hard to track.

是的。虽然销毁对套接字的引用可能会导致垃圾收集器完成它,但这并没有指定它将被关闭。在许多情况下,这是特定于实现的,并且有时会由于性能甚至难以跟踪的微小错误而与设计脱轨。

Keeping a reference anywhereis a surebet that it won't be, even with WeakReferences.

即使使用 Wea​​kReferences,在任何地方都保留引用是肯定的,它不会。

Now the OS has a limited(due to its design) number of sockets it can give. As you open more and more sockets, the OS comes under pressure and eventually runs out of sockets, causing the failure of either Java or another program. In addition, depeding on socket options you or defaults may set, this socket may send keepalives, exhausting resources on the other endpoint as well.

现在操作系统可以提供的套接字数量有限(由于其设计)。随着您打开越来越多的套接字,操作系统会承受压力并最终耗尽套接字,从而导致 Java 或其他程序失败。此外,根据您或默认值可能设置的套接字选项,此套接字可能会发送 keepalive,从而耗尽其他端点上的资源。

On exit, it is closed by the socket registering a shutdown action in its constructor to close it, and/or the OS's automatic cleanup.

在退出时,它由套接字在其构造函数中注册关闭操作来关闭它,和/或操作系统的自动清理。

You should neverrely on OS/JVM behavior or finalization to close your sockets,especially if you have multiple sockets, even if you don't plan to use all of them at the same time.

永远不应该依赖 OS/JVM 行为或终结来关闭您的套接字,尤其是当您有多个套接字时,即使您不打算同时使用所有套接字。

回答by Victor Sorokin

Yes, it's necessary to release any finite resources, because otherwise your app will make other processes on the host starve for resources and won't be able to sustain in a long run

是的,有必要释放任何有限的资源,否则你的应用程序会使主机上的其他进程资源匮乏,无法长期维持

Here's how I do such task:

这是我执行此类任务的方法:

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
            }
        }
    }
}

Additionally, moving GUI code to other class would be a nice idea, to keep things clean.

此外,将 GUI 代码移动到其他类将是一个不错的主意,以保持整洁。

回答by Stephen C

One answer is that you really ought to close()resources ... even if it is not strictly necessary.

一个答案是你真的应该close()资源......即使它不是绝对必要的。

Why?

为什么?

Because, the circumstances that (hypothetically) mean that it is not strictly necessary could change!

因为,(假设)这不是绝对必要的情况可能会改变!

And ... lets face it ... it is easyto write code to automatically close a server socket.

而且......让我们面对现实......编写代码来自动关闭服务器套接字很容易

But read on ...

但是请继续阅读...



It's REALLY necessary to close the ServerSocket in this case?

在这种情况下真的有必要关闭 ServerSocket 吗?

It depends.

这取决于。

  • If you know for certainthat run()is only ever going to run once and then the application is always going to completely shut down (modulo caveats below), then not closing the ServerSocketwon't cause any actual harm.

  • Otherwise, failure to close() couldcause harm.

  • 如果您确定run()只会运行一次,然后应用程序总是会完全关闭(下面的模数警告),那么不关闭ServerSocket不会造成任何实际伤害。

  • 否则,未能 close()可能会造成伤害。

The "harm" could take a couple of forms:

“伤害”可能有以下几种形式:

  • The server socket could hold a "lock" on a port, preventing another instance of the application from listening on that port (depending on the OS).

  • The server socket could be a limited resource, and if the run()method is called multiple times (without close()-ing) the application could "grab" all available instances of that resource, preventing other applications from acquiring an instance.

  • 服务器套接字可以在端口上保持“锁定”,防止应用程序的另一个实例侦听该端口(取决于操作系统)。

  • 服务器套接字可能是一种有限资源,如果run()多次调用该方法(不带close()-ing),应用程序可以“获取”该资源的所有可用实例,从而防止其他应用程序获取实例。

The harm could also be inflicted on the application instance itself, if run()is called multiple times.

如果run()多次调用,也可能对应用程序实例本身造成损害。



The ServerSocket closes itself by its own when the software is shut down?

ServerSocket在软件关闭时自行关闭?

The ServerSocket doesn't "close itself" unless it is garbage collected and finalized. And you can't rely on either happening when a JVM exits. But in a broader sense, the underlying server socket resource is typicallyclosed (released) automatically when the JVM exits.

ServerSocket 不会“自行关闭”,除非它被垃圾收集并最终确定。并且您不能依赖 JVM 退出时发生的任何一种情况。但从更广泛的意义上讲,底层服务器套接字资源通常在 JVM 退出时自动关闭(释放)。

But the complete answer actually depends on what you mean by "the software is shut down", and also on the nature of the platform. For example:

但完整的答案实际上取决于您所说的“软件已关闭”是什么意思,以及平台的性质。例如:

  • If shutdown means that the JVM exits completely, and the corresponding process that "owns" the underlying server socket (from the OS perspective) alsoexits, then the OS will close that socket ... at least on modern Unix / Linux / Windows platforms. (Note that Android is Linux under the hood)

  • If "the software" is something like a webapp running in a web container, the "shutdown" can mean something different to JVM exit, and the ServerSocket could continue to exist (and not be closed) after the shutdown.

  • If the JVM is embedded in something else (e.g. in a large C / C++ application) and that something else doesn't exit, then the OS won't know to release the underlying server socket.

  • If you are running on platform where the OS doesn't provide the same level of process separation / resource management as on Unix / Linux / (modern) Windows, then the underlying server socket may not beclosed by the OS on process exit. (This scenario might apply for a Java implementation on an embedded system ...)

  • 如果关闭意味着 JVM 完全退出,并且“拥有”底层服务器套接字的相应进程(从操作系统的角度来看)退出,那么操作系统将关闭该套接字......至少在现代 Unix / Linux / Windows 平台上. (请注意,Android 是 Linux 引擎盖下的)

  • 如果“软件”类似于在 Web 容器中运行的 Web 应用程序,那么“关闭”可能意味着与 JVM 退出不同的东西,并且 ServerSocket 可以在关闭后继续存在(而不是关闭)。

  • 如果 JVM 嵌入在其他东西中(例如,在大型 C/C++ 应用程序中)并且其他东西没有退出,那么操作系统将不知道释放底层服务器套接字。

  • 如果您在操作系统不提供与 Unix/Linux/(现代)Windows 上相同级别的进程分离/资源管理的平台上运行,那么底层服务器套接字可能不会在进程退出时被操作系统关闭。(这种情况可能适用于嵌入式系统上的 Java 实现......)



At any rate, it is not hard to do the right thing. In Java 7 and later:

无论如何,做正确的事并不难。在 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
    }
}

(Though, I don't see the point of catching HeadlessExceptionin what appears to be an action called from a button listener.)

(虽然,我不认为捕捉HeadlessException似乎是从按钮侦听器调用的动作的意义。)