2011-04-11 87 views
5

我对TCP客户端 - 服务器通信的结构如下:Java:停止线程化TCP服务器的好方法?

  • 在服务器启动时服务器启动 受体螺纹,接受客户 连接并传递的ServerSocket 给它。
  • 当客户端连接到达, 受体线程调用accept()上 的ServerSocket并提交客户 的处理作业工作线程 (由执行/线程池),并提供客户端套接字给它。
  • 工人循环从 客户端套接字流中读取数据,对其进行处理并发送回复。

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

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

回答

3

您的模型正常工作。中断IO等非可中断结构的最好方法是关闭套接字。你当然可以在进入阻塞状态之前处理它,但是如果IO功能不会对中断做出反应,你真的没有很多好的选择

2

我会建议使用布尔标志,工人定期检查。调用标志shouldStop,如果它设置为true,则工人清理并死亡。遵循这种方法将允许您执行一些清理代码,以便不会使资源悬挂等。

+0

当I/O中的工作者被阻塞时,我无法检查这个标志 – 2011-04-11 17:24:39

+0

最佳做法是使用Thread.interrupted()。这是标准的解决方案,可以在ThreadPool中正常工作。 – 2011-04-11 19:04:45

+0

@Andrey Vityuk Thread.interrupted实际上不是很好的做法,因为它重置了中断标志。你可能意味着Thread.interrupt或Thread.isInterrupted。这就是说,正如我在我的回答中所说的,许多IO构造不考虑线程中断,因此(尽管我部分同意你的评论)它不适用于这种情况。 – 2011-04-12 00:30:53

2

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

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

  • 您必须先停止接受服务器中的新连接 。
  • 然后您可以等待 当前工作线程完成 他们的工作,然后关闭 服务器并正式关闭。
  • 或者你强制工作线程 关闭与
    客户他们的连接(可能使用某种标志的
    的建议)。这可能是 意味着一些清理,以保持数据 一致,例如恢复 传输或您在文件或内存中完成的任何类型的更改 。

根据我的理解,关闭与服务器端客户端的连接应该会导致客户端获得EOF。

[编辑-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 
      } 
     } 
    } 
+0

我对此非常了解。 “那么你可以等待当前的工作线程完成他们的工作” - 如果你再次读到我的问题,你会发现这是一个问题。工作人员可以通过从套接字流中读取来阻止。问题是如何优雅地打断他们。标志在这里不起作用,因为工作人员在处于被阻止的I/O状态时无法检查它 – 2011-04-11 15:42:56

+0

“你不能简单地停止服务器。”实际上,如果你的服务器设计正确(ACID事务和所有) 。导致数据库提交的更改被认为发生了,并且不会发生的更改不会发生。使这项工作顺利进行是将数据库与中间绑定的业务逻辑和Web前端分离的一个很好的理由。 – 2011-04-11 17:30:13