0

Explanation

I'm revisiting the project I used to teach myself 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.

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.

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.

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

  • "I don't like relying on exceptions for normal operation unless it's necessary" OMG another one. It's necessary. The `setSoTimeout()` mechanism is provided for exactly this purpose, and `SocketTimeoutException` is part of its interface. Don't let arbitrary programming aesthetics get in the way of implementing correct code. And in what way is forcing an `IOException: socket closed` any better than catching a `SocketTimeoutException`? – user207421 Oct 30 '14 at 22:43
  • I wasn't sure if it was necessary in this case, that's why I was asking. And my original thought was that throwing one Exception would be better that potentially throwing one every 2 seconds. – Kymon Lown Oct 31 '14 at 08:03

3 Answers3

1

The problem with second approach is that the server will die if an exception occurs in the while loop.

The first approach is better, though you might want to add logging exceptions using Log4j.

while (running){
    try{
        client = serverSocket.accept();
        createComms(client);
    } catch (IOException ex){
        // Log errors
        LOG.warn(ex,ex);
    }
}
Slava Imeshev
  • 1,360
  • 10
  • 14
  • Cheers, Your answer pointed me to avoid using SOTimeout and just close the socket to force an exception on close, a much cleaner and simpler way :) – Kymon Lown Nov 07 '14 at 15:55
0

Non-blocking IO is what you're looking for. 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.

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. I have a small example of that here, as well as a non-blocking ServerSocket that doesnt use a selector

EDIT: In case something goes wrong with my link, here is the example of non-blocking IO, without a selector, accepting a connection:

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
               }
          }
     }
}
Community
  • 1
  • 1
Vince
  • 14,470
  • 7
  • 39
  • 84
-1

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. The method can throw all kinds of exceptions though (see the 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.

vanOekel
  • 6,358
  • 1
  • 21
  • 56
  • The second approach is identical for the reasons he mentioned. It just exchanges an `IOException` for a `SocketTimeoutException`. – user207421 Oct 30 '14 at 22:44