';ServerSocket.accept()';不带SocketTimeoutException的循环(Java)(替代解决方案)

';ServerSocket.accept()';不带SocketTimeoutException的循环(Java)(替代解决方案),java,multithreading,sockets,exception,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); Soc

解释

我正在重温我曾经自学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

非阻塞IO是您需要的。如果当前没有要接受的连接,它将返回
null
,而不是阻塞直到返回
SocketChannel
(非阻塞替代
Socket

这将允许您删除超时,因为不会有任何阻塞

您还可以注册一个
选择器
,它会在有连接要接受或有数据要读取时通知您。我有一个小例子,以及一个不使用选择器的非阻塞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
               }
          }
     }
}

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

第一种方法更好,尽管您可能希望使用Log4j添加日志异常

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

第二种方法更好(因为您提到的原因:在正常程序流中依赖异常不是一种好的做法),尽管您的代码建议
serverSocket.accept()
可以返回
null
,但它不能返回。不过,该方法可以抛出各种异常(请参见)。您可能希望捕获这些异常:没有很好的理由,服务器不应该停机


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

“我不喜欢依赖异常进行正常操作,除非有必要”OMG另一个异常。这是必要的。
setSoTimeout()
机制正是为此目的而提供的,而
SocketTimeoutException
是其接口的一部分。不要让任意的编程美学妨碍实现正确的代码。强制执行
IOException:socketclosed
比捕获
SocketTimeoutException
更好吗?我不确定在这种情况下是否有必要,这就是为什么我要问的原因。我最初的想法是,抛出一个异常比每2秒抛出一个异常要好。第二种方法是相同的,因为他提到的原因。它只是将
IOException
交换为
SocketTimeoutException
。感谢您的建议!是时候修补新玩具了=3张桌子,你的回答告诉我要避免使用SOTimeout,只需关闭插座即可强制关闭异常,这是一种更干净、更简单的方法:)