【问题标题】:How to unblock a thread blocked on ServerSocket.accept()?如何解除阻塞在 ServerSocket.accept() 上的线程?
【发布时间】:2011-12-20 00:43:11
【问题描述】:

我有一个带有此代码的服务器线程:

public void run() {
    try {
        ServerSocket server;
        EneaLog.printLog("Server is running.");
        server = new ServerSocket(this.portnumber);

        while (true) {
            new EneaServerConnection(server.accept(), this.project,stopped).start();
            if (stopped) {
                EneaLog.printLog("Server safe-shutdown completed.");
                EneaLog.printLog("Hi!");
                server.close();
                return;
            }
        }
    } catch (IOException ex) {
        Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex);
        project.getExceptionHandler().handler(ex);
    }
}

还有这样的关机方法:

public void shutdown() {
    EneaLog.printLog("Server shutdown NOW!");
    stopped = true;
}

我希望关闭可以解除阻塞等待 server.accept() 的线程,否则我必须在服务器关闭之前等待连接。

我不能在shutdown() 中执行server.close(),因为我必须向已注册的客户端发出服务器正在关闭的信号。

有什么想法吗?

【问题讨论】:

    标签: java sockets


    【解决方案1】:

    我尝试设计我的代码,以便它可以通过中断“关闭”。主要是因为Java并发包中的Executor框架使用interrupt取消正在运行的任务。此外,“关闭”任务不必知道被杀死任务的任何内部结构。

    但是,对accept 的调用不会响应中断除非它是created from a ServerSocketChannel. 使用ServerSocket 构造函数创建的服务器将忽略中断,我还没有找到重新配置它的方法。

    如果您无法更改创建服务器的代码,请安排另一个线程在服务器套接字上调用close。这也会在 accept 上阻塞的线程中引发异常,无论用于创建服务器套接字的方法如何。

    在使用 SSL 时,这确实是一个很大的痛苦。 JSSE 套接字不是从 InterruptibleChannel 创建的,并且不会响应线程上的简单中断。


    我刚刚注意到问题是在不通知客户端的情况下无法关闭服务器。成功中断套接字会导致其关闭。

    在调用accept 时这应该不是问题,因为如果服务器套接字在接受中被阻止,则客户端不会连接。这应该只是代表当前连接的Socket 实例的问题。

    如果这不满足通知要求,则可能需要重新设计以在非阻塞模式下使用 NIO 的ServerSocketChannel

    【讨论】:

    • 嗯很好的答案..也许我改变了解决问题的方法。我使用 try-catch 在客户端管理服务器关闭。
    • 我想知道你是否可以让服务器从一个单独的线程创建另一个客户端套接字,一旦接受()解除阻塞,现在解除阻塞的循环可以以某种方式立即询问该客户端套接字..知道它是它的自己的客户端套接字...并设置一个标志以退出无限循环。从未尝试过,但也许需要考虑一下
    • 可能,但听起来您需要能够修改服务器代码。如果你有,只需使用ServerSocketChannel
    【解决方案2】:

    您应该能够从另一个线程关闭套接字。

    【讨论】:

      【解决方案3】:

      中断(依赖于中断点,就像取消依赖于取消点一样)也不会关闭(accept 不会响应关闭其文件描述符)。您必须与接受通信(尝试发送到,带有关闭通知)以通知它不要继续接受。至少在 linux 上是这样的;不知道在其他平台上是什么样子的。

      【讨论】:

      • 你最后是怎么解决这个问题的?很多人说 close 会起作用,但在我在 linux 上运行的情况下它不起作用。
      【解决方案4】:

      我也遇到过同样的问题。我的工作解决方案包括关闭 ServerSocket 对象 (serverSocket.close()) ;这样做会导致 accept() 方法抛出一个 SocketException,这正是你想要做的。

      文森特

      【讨论】:

        【解决方案5】:

        你试过Thread.interrupt()吗?

        如果此线程在 I/O 中被阻塞 可中断操作 频道 那么频道将是 关闭,线程的中断状态 将被设置,线程将 收到 ClosedByInterruptException。

        如果这个线程在一个 选择器然后线程的中断 将设置状态并将返回 立即从选择 操作,可能有一个非零 值,就像选择器的 唤醒方法被调用。

        【讨论】:

        • 你需要在你想中断的线程(即被阻塞的线程)上调用它
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-06
        • 1970-01-01
        相关资源
        最近更新 更多