'的ServerSocket.accept()'循环没有SocketTimeoutException(Java)(替代解决方案)

时间:2014-10-30 16:41:27

标签: java multithreading sockets exception

解释

我正在重新审视我过去自学Java的项目。

在这个项目中,我希望能够阻止服务器接受新客户端,然后在退出JVM之前执行一些“清理”操作。

在该项目中,我使用以下样式进行客户端接受/处理循环:

//Exit loop by changing running to false and waiting up to 2 seconds
ServerSocket serverSocket = new ServerSocket(123);
serverSocket.setSoTimeout(2000);

Socket client;    
while (running){ // 'running' is a private static boolean 
    try{
        client = serverSocket.accept();
        createComms(client); //Handles Connection in New Thread
    } catch (IOException ex){
        //Do Nothing
    }
}

在这种方法中,如果没有客户端连接,则每2秒抛出一次SocketTimeoutException,除非有必要,否则我不喜欢依赖异常进行正常操作。

我一直在尝试使用以下样式来尝试最小化依赖异常进行正常操作:

//Exit loop by calling serverSocket.close()
ServerSocket serverSocket = new ServerSocket(123);

Socket client;    
try{
    while ((client = serverSocket.accept()) != null){  
        createComms(client); //Handles Connection in New Thread
    }
} catch (IOException ex){
    //Do Nothing
}

在这种情况下,我的意图是只有在调用serverSocket.close()或出现问题时才会抛出异常。

问题

这两种方法有什么显着差异,还是它们都是可行的解决方案?

我完全是自学成才,所以我不知道我是否无缘无故地重新发明了这个轮子,或者我是不是已经找到了好的东西。

我已经潜伏了一段时间,这是我第一次找不到我需要的东西。

请随意提出完全不同的方法= 3

3 个答案:

答案 0 :(得分:1)

第二种方法的问题是如果while循环中发生异常,服务器将会死亡。

第一种方法更好,但您可能希望使用Log4j添加日志记录异常。

while (running){
    try{
        client = serverSocket.accept();
        createComms(client);
    } catch (IOException ex){
        // Log errors
        LOG.warn(ex,ex);
    }
}

答案 1 :(得分:0)

非阻塞IO是您正在寻找的。如果返回SocketChannelSocket的非阻塞替代方法),则返回null,如果当前没有要接受的连接,则不会阻止。

这将允许您删除超时,因为没有任何阻止。

您还可以注册一个Selector,它会在有接受连接或有数据需要时通知您。我有一个here的小例子,以及一个不使用选择器的非阻塞ServerSocket

编辑:如果我的链接出现问题,这里是非阻塞IO的示例,没有选择器,接受连接:

class Server {
     public static void main(String[] args) throws Exception {
          ServerSocketChannel ssc = ServerSocketChannel.open();
          ssc.configureBlocking(false);

          while(true) {
               SocketChannel sc = ssc.accept();

               if(sc != null) {
                    //handle channel
               }
          }
     }
}

答案 2 :(得分:-1)

第二种方法更好(出于你提到的原因:依赖正常程序流程中的例外不是一个好习惯)尽管你的代码表明serverSocket.accept()可以返回null,但它不能。该方法可以抛出各种异常(参见api-docs)。您可能希望捕获这些异常:服务器不应该在没有充分理由的情况下关闭。

我一直在使用第二种方法取得了很大成功,但添加了一些代码以使其更稳定/更可靠:请参阅我对它的看法here(单元测试here)。其中一个清理'要考虑的任务是给处理客户端通信的线程一些时间,以便这些线程可以完成或正确地通知客户端连接将被关闭。这可以防止客户端在连接突然丢失/关闭之前不确定服务器是否完成了重要任务的情况。