简体   繁体   English

Java - 关闭没有异常的ServerSocket?

[英]Java - closing a ServerSocket without Exceptions?

For years I've been wondering what the correct way to close a listening ServerSocket in Java is. 多年来我一直想知道在Java中关闭监听ServerSocket的正确方法是什么。 My implementations always work like this, they: 我的实现总是像这样工作,他们:

  1. Create a new ServerSocket(int). 创建一个新的ServerSocket(int)。
  2. Start a thread that calls its accept() method in a while (true) loop. 启动一个在while(true)循环中调用其accept()方法的线程。
  3. Start another thread when accept() returns (client connects) that reads from the client until it disconnects. 当accept()返回(客户端连接)从客户端读取直到它断开连接时,启动另一个线程。 The accept thread then continues with another accept() call. 接受线程然后继续另一个accept()调用。

But when I want to close the ServerSocket because my application is exiting, I've never found another way of doing so other than calling it's close() method (after I've closed all client Sockets), which causes accept() to throw a SocketException, I catch that and break from the while (true) loop in the accept thread, causing all my threads to exit. 但是当我想要关闭ServerSocket因为我的应用程序正在退出时,除了调用它的close()方法(在我关闭所有客户端套接字之后)之外我从未找到另一种方法,这会导致accept()抛出一个SocketException,我抓住它并从接受线程中的while(true)循环中断,导致我的所有线程都退出。

I think this is ugly, strictly speaking there is no exception occurring, closing my ServerSocket is part of my programs normal operation. 我认为这很难看,严格来说没有异常发生,关闭我的ServerSocket是我程序正常运行的一部分。

Is there really no other way of doing this without causing an Exception to be thrown? 在没有引发异常的情况下,真的没有其他办法吗?

Thanks. 谢谢。

I've never found another way of doing so other than calling it's close() method (after I've closed all client Sockets), 除了调用它的close()方法(在我关闭所有客户端套接字后)之外,我从未发现过这样做的另一种方式,

You can set a flag closed = true; 你可以设置一个标志closed = true; and open a dummy connection to wake up the accept()ing thread which checks the flag before continuing. 并打开一个虚拟连接来唤醒在继续之前检查标志的accept()线程。

which causes accept() to throw a SocketException, 导致accept()抛出SocketException,

A SocketClosedException which is expected behaviour here. 一个SocketClosedException,这是预期的行为。

I catch that and break from the while (true) loop in the accept thread, 我抓住了它,并从接受线程中的while(true)循环中断开,

If you catch it outside the loop, you don't need to also break out of the loop. 如果你在循环之外捕获它,你也不需要打破循环。 If the exception is thrown and you have set closed = true you can discard the exception. 如果抛出异常并且您设置了closed = true ,则可以放弃该异常。

BTW I would do 顺便说一下,我会这样做

while(!serverSocket.isClosed()) {

causing all my threads to exit. 导致我的所有线程退出。

There is no particular reason you need to have this, but you can choose to do this if you want. 您没有特别需要这样做,但如果您愿意,您可以选择这样做。

I think this is ugly, strictly speaking there is no exception occurring, 我认为这很难看,严格来说没有异常发生,

An exceptional condition is happening. 一种特殊情况正在发生。 What is not happening is an Error. 没有发生的是错误。

closing my ServerSocket is part of my programs normal operation. 关闭我的ServerSocket是我的程序正常运行的一部分。

Or you could say it is operating normally when it is running and not shutting down. 或者你可以说它正在运行而没有关机时正常运行。

Thanks for your comment. 谢谢你的评论。

You can set a flag closed = true; 你可以设置一个标志closed = true; and open a dummy connection to wake up the accept()ing thread which checks the flag before continuing. 并打开一个虚拟连接来唤醒在继续之前检查标志的accept()线程。

Opening a new Socket to close an existing one? 打开一个新的Socket以关闭现有的Socket? IMO that is one of the worst sins ever. 国际海事组织是有史以来最严重的罪行之一。

A SocketClosedException which is expected behaviour here. 一个SocketClosedException,这是预期的行为。

Actually it doesn't throw a SocketClosedException but a SocketException, the following code: 实际上它不会抛出SocketClosedException而是抛出SocketException,代码如下:

try {
    final ServerSocket ss = new ServerSocket(1234);
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                ss.accept();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    }).start();
    ss.close();
} catch (Exception ex) {
    ex.printStackTrace();
}

Produced the following output: 产生以下输出:

java.net.SocketException: Socket is closed
at java.net.ServerSocket.accept(ServerSocket.java:494)
at Main$1.run(Main.java:12)
at java.lang.Thread.run(Thread.java:744)

If you catch it outside the loop, you don't need to also break out of the loop. 如果你在循环之外捕获它,你也不需要打破循环。 If the exception is thrown and you have set closed = true you can discard the exception. 如果抛出异常并且您设置了closed = true,则可以放弃该异常。

BTW I would do 顺便说一下,我会这样做

while(!serverSocket.isClosed()) { while(!serverSocket.isClosed()){

That would work, but I think this should work without setting flags and catching Exceptions. 这样可行,但我认为这应该可以在不设置标志和捕获异常的情况下工作。

An exceptional condition is happening. 一种特殊情况正在发生。 What is not happening is an Error. 没有发生的是错误。

Or you could say it is operating normally when it is running and not shutting down. 或者你可以说它正在运行而没有关机时正常运行。

I don't agree. 我不同意。 It is normal behaviour for applications to be exiting. 应用程序退出是正常行为。 They may always do so. 他们可能总是这样做。

Why doesn't the accept() method just returns null when close() is called? 为什么在调用close()时accept()方法只返回n​​ull? That would be so much easier. 那会容易得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM