Java:停止线程 TCP 服务器的好方法?

发布于 2024-10-31 17:53:41 字数 570 浏览 4 评论 0原文

我有以下 TCP 客户端-服务器通信结构:

  • 在服务器启动时服务器启动 接受者线程,接受客户端 连接并传递 ServerSocket 到它。
  • 当客户端连接到达时, 接受器线程调用accept() ServerSocket并提交客户端 处理作业到工作线程 (通过执行器/线程池)并向其提供客户端套接字。
  • 循环中的工作程序读取数据 客户端套接字流,处理它并发送回复。

问题是如何优雅地停止整个系统?我可以通过关闭 ServerSocket 来停止接受器线程。它将导致accept()阻塞调用抛出SocketException。但如何阻止工人呢?他们从流中读取,并且此调用被阻塞。根据这个流不会抛出InterruptedException,因此worker不能被中断()。

看来我需要从另一个线程关闭工作套接字,对吧?为此,应将套接字设置为公共字段,或者应在工作程序中提供方法来关闭它。这会好吗?或者我的整个设计可能有缺陷?

I have the following structure for TCP client-server communication:

  • On server startup server starts
    acceptor thread, that accepts client
    connections and passes ServerSocket
    to it.
  • When a client connection arrives,
    acceptor thread calls accept() on
    ServerSocket and submits client
    processing job to worker thread
    (by executor/thread pool) and provides client socket to it.
  • Worker in loop reads data from
    client socket stream, processes it and sends replies.

The question is how to gracefully stop the whole system? I can stop acceptor thread by just closing ServerSocket. It will cause accept() blocking call to throw SocketException. But how to stop workers? They read from stream and this call is blocking. According to this streams does not throw InterruptedException and thus worker cannot be interrupt()'ed.

It looks like I need to close worker socket from another thread, right? For this, socket should be made a public field or a method should be provided in worker to close it. Will this be nice? Or may be my whole design is flawed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

滥情稳全场 2024-11-07 17:53:41

您的模型工作正常。中断不可中断结构(如 IO)的最佳方法是关闭套接字。当然,您可以在进入阻塞状态之前处理它,但是如果 IO 函数不对中断做出反应,您实际上没有很多好的选择

Your model works appropriately. The best way of interrupting non-interruptable constructs like IO is to close the socket. You can of course handle it before you go into a blocking state, but if the IO functions don't react to interruption you dont really have many good options

酷炫老祖宗 2024-11-07 17:53:41

我建议使用工人定期检查的布尔标志。调用标志 shouldStop ,如果它设置为 true,那么工作线程会清理然后终止。遵循此方法将允许您实现一些清理代码,这样您就不会留下资源挂起等。

I would suggest using a boolean flag that the workers check periodically. Call the flag shouldStop and if it's set to true, the worker cleans up and then dies. Following this method would allow you to implement some clean-up code so you don't leave resources hanging, etc.

傲娇萝莉攻 2024-11-07 17:53:41

您不能简单地停止服务器。关闭过程可能需要一段时间才能进行清理,因为您需要确保一致性。

想象一下数据库服务器,如果您在执行事务时简单地将其关闭,则可能会导致其数据不一致。这就是为什么关闭服务器通常需要一段时间的原因。

  • 你必须首先停止接受新的
    服务器中的连接。
  • 然后您可以等待
    当前要完成的工作线程
    他们的工作,然后关闭
    服务器并正式关闭。
  • 或者你强制工作线程
    关闭与
    的联系
    客户端(可能使用某种
    如建议的标志)。这可能
    意味着进行一些清理以留下数据
    一致,例如恢复
    交易或任何类型的变更
    你已经在文件或内存中完成了。

据我所知,关闭与服务器端客户端的连接应该会导致客户端收到 EOF。

[EDIT-1]

我对这个问题进行了一些研究,只是因为我有一段时间没有使用套接字并且因为我发现这个问题很有趣。我认为正如其他人已经指出的那样,唯一的选择是关闭套接字,根据Javadocs,它会自动关闭输入和输出流/

如果线程有可能不是IO阻塞,而是处于等待状态状态或睡眠,我认为仍然建议为给定套接字的相应工作线程发出 Thread.interrupt() ;因为无法确定每个线程的阻塞状态。

public static class IOServerWorker implements Runnable{

        private Socket socket;

        public IOServerWorker(Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            String line = null;
            try{
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while( (line = reader.readLine())!=null){
                    System.out.println(line);
                }
                reader.close();
            }catch(IOException e){
                //TODO: do cleanup here
                //TODO: log | wrap | rethrow exception
            }
        }
    }

You must not simply stop the server. The shutdown process might take a while while cleanup occurs because you need to ensure consistency.

Imagine a database server, if you simply shut it down while it is carrying out transactions you may leave its data inconsistent. That's why it typically takes a while to shutdown the server.

  • You must first stop accepting new
    connections in the server.
  • Then you can either wait for the
    current worker threads to finish
    their work and then close the
    server and shutdown officially.
  • Or you force the worker threads to
    close their connections with the
    client (probably using some sort
    of flag as suggested). This might
    imply some cleanup to leave data
    consistent, for instance revert
    trasnsactions or any kind of changes
    you have done in files or in memory.

Closing the connections with the clients in the server side should cause the clients to get a EOF on their sides as far as I understand.

[EDIT-1]

I have delved a bit on the issue, just because I had not used sockets in a while and because I found the question interesting. I think as it has been well pointed out by others, the only option is to close the socket, which according got Javadocs will automatically close the input and output streams/

If there are chances that the thread is not IO-blocked, but in wait state or sleeping, I think it is still recommended to issue a Thread.interrupt() for the corresponding worker thread of a given socket; because there cannot be certainty of the blocking of state of every thread.

public static class IOServerWorker implements Runnable{

        private Socket socket;

        public IOServerWorker(Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            String line = null;
            try{
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while( (line = reader.readLine())!=null){
                    System.out.println(line);
                }
                reader.close();
            }catch(IOException e){
                //TODO: do cleanup here
                //TODO: log | wrap | rethrow exception
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文