简体   繁体   English

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

[英]'ServerSocket.accept()' Loop Without SocketTimeoutException (Java) (Alternative Solution)

Explanation 说明

I'm revisiting the project I used to teach myself Java. 我正在重温过去自学Java的项目。

In this project I want to be able to stop the server from accepting new clients and then perform a few 'cleanup' operations before exiting the JVM. 在此项目中,我希望能够停止服务器接受新客户端,然后在退出JVM之前执行一些“清理”操作。

In that project I used the following style for a client accept/handle loop: 在该项目中,我对客户端接受/处理循环使用了以下样式:

//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
    }
}

In this approach a SocketTimeoutException will be thrown every 2 seconds, if there are no clients connecting, and I don't like relying on exceptions for normal operation unless it's necessary. 在这种方法中,如果没有客户端连接,则会每2秒抛出SocketTimeoutException,除非有必要,否则我不希望依赖异常来进行正常操作。

I've been experimenting with the following style to try and minimise relying on Exceptions for normal operation: 我一直在尝试使用以下样式来尝试最大程度地减少对异常的依赖:

//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
}

In this case my intention is that an Exception will only be thrown when I call serverSocket.close() or if something goes wrong. 在这种情况下,我的意图是仅在我调用serverSocket.close()或出现问题时才抛出异常。

Question

Is there any significant difference in the two approaches, or are they both viable solutions? 两种方法之间是否存在重大差异,或者它们都是可行的解决方案?

I'm totally self-taught so I have no idea if I've re-invented the wheel for no reason or if I've come up something good. 我完全是自学成才的,所以我不知道我是否无缘无故地重新发明了车轮,或者我想出了什么好东西。

I've been lurking on SO for a while, this is the first time I've not been able to find what I need already. 我已经潜伏了一段时间,这是我第一次找不到我需要的东西。

Please feel free to suggest completely different approaches =3 请随意提出完全不同的方法= 3

The problem with second approach is that the server will die if an exception occurs in the while loop. 第二种方法的问题在于,如果while循环中发生异常,服务器将死亡。

The first approach is better, though you might want to add logging exceptions using Log4j. 第一种方法更好,尽管您可能想使用Log4j添加日志记录例外。

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

Non-blocking IO is what you're looking for. 您正在寻找无阻塞IO。 Instead of blocking until a SocketChannel (non-blocking alternative to Socket ) is returned, it'll return null if there is currently no connection to accept. 如果当前没有连接可以接受,它将返回null ,而不是阻塞直到返回SocketChannelSocket的非阻塞替代方法)。

This will allow you to remove the timeout, since nothing will be blocking. 由于没有任何阻塞,因此您可以删除超时。

You could also register a Selector , which informs you when there is a connection to accept or when there is data to read. 您还可以注册一个Selector ,它会在有连接要接受或有数据要读取时通知您。 I have a small example of that here , as well as a non-blocking ServerSocket that doesnt use a selector 在这里有一个小例子,以及不使用选择器的非阻塞ServerSocket

EDIT: In case something goes wrong with my link, here is the example of non-blocking IO, without a selector, accepting a connection: 编辑:万一我的链接出了问题,这是无阻塞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
               }
          }
     }
}

The second approach is better (for the reasons you mentioned: relying on exceptions in normal program flow is not a good practise) allthough your code suggests that serverSocket.accept() can return null , which it can not. 第二种方法更好(由于您提到的原因:在正常的程序流中依赖异常不是一个好习惯), serverSocket.accept()您的代码建议serverSocket.accept()可以返回null ,但不能。 The method can throw all kinds of exceptions though (see the api-docs ). 该方法可以引发各种异常(请参阅api-docs )。 You might want to catch those exceptions: a server should not go down without a very good reason. 您可能想捕获这些异常:没有充分的理由服务器就不应停机。

I have been using the second approach with good success, but added some more code to make it more stable/reliable: see my take on it here (unit tests here ). 我一直使用具有良好的成功第二种方法,但增加了一些代码,使其更加稳定/可靠:看到我拿上它在这里 (单元测试这里 )。 One of the 'cleanup' tasks to consider is to give some time to the threads that are handling the client communications so that these threads can finish or properly inform the client the connection will be closed. 要考虑的“清理”任务之一是给正在处理客户端通信的线程一些时间,以便这些线程可以完成或正确通知客户端连接将被关闭。 This prevents situations where the client is not sure if the server completed an important task before the connection was suddenly lost/closed. 这样可以防止客户端不确定在突然丢失/关闭连接之前服务器是否完成了重要任务的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM