22

This is a simple TCP server. How can i close the socket when the program is terminated? I have using try/finally and try to close the socket. But it doesn't run the finally block when I exit the program.

Anyone can have idea on how to close the socket in a proper way?

try {
        socket = new ServerSocket(port);
        System.out.println("Server is starting on port " + port + " ...");
    }catch (IOException e){
        System.out.println("Error on socket creation!");
    }

    Socket connectionSocket = null;
    try{
        while(true){            
            try{
                connectionSocket = socket.accept();
                Thread t =  new Thread(new ClientConnection(connectionSocket));
                t.start();
            }catch (IOException e) {
                System.out.println("Error on accept socket!");
            }
        }
    }finally{
        this.socket.close();
        System.out.println("The server is shut down!");
    }
om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
TheOneTeam
  • 25,806
  • 45
  • 116
  • 158
  • 1
    call the sockets `close()` method in your finally block, or now with java 7 you can use the try-with-resources block, and it will close them for you. http://www.javacodegeeks.com/2011/07/java-7-try-with-resources-explained.html – Hunter McMillen Nov 08 '11 at 14:28
  • 1
    You also need a null check before calling `close()` in case the `ServerSocket` constructor throws an exception. – unholysampler Nov 08 '11 at 14:38
  • @Kit Ho, How is the application terminated? – mre Nov 08 '11 at 14:41
  • 1
    @mre: just by pressing the terminate button in eclipse or control-c in console. I wanna add a final msg saying "the server is shut down", in python, it is easy to do that, but don't know in java – TheOneTeam Nov 08 '11 at 14:44
  • 6
    I would catch IOException outside your loop. It is highly unlikely you can recover from this error so looping infinitely might not be a good idea. – Peter Lawrey Nov 08 '11 at 15:27
  • 2
    @Peter Lawrey +1, or else add a `break` in the catch block. – user207421 Nov 09 '11 at 01:39

5 Answers5

18

After creating your ServerSocket, you could add a ShutdownHook to close it on JVM termination, something like this:

Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
    try {
        socket.close();
        System.out.println("The server is shut down!");
    } catch (IOException e) { /* failed */ }
}});

Invoking ServerSocket#close will terminate the blocking ServerSocket.accept call, causing it to throw a SocketException. However, note that your current handling of IOException in the while loop means you will then re-enter the while loop to attempt accept on a closed socket. The JVM will still terminate, but it's a bit untidy.

Shutdown hooks do not run if you terminate a console application in Eclipse (on Windows at least). But they do run if you CTRL-C Java in a normal console. For them to run, you need the JVM to be terminated normally, e.g. SIGINT or SIGTERM rather than SIGKILL (kill -9).

A simple program which you can execute in Eclipse or a console will demonstrate this.

public class Test implements Runnable {

  public static void main(String[] args) throws InterruptedException {
    final Test test = new Test();
    Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
      test.shutdown();
    }});
    Thread t = new Thread(test);
    t.start();
  }

  public void run() {
    synchronized(this) {
      try {
        System.err.println("running");
        wait();
      } catch (InterruptedException e) {}
    }
  }

  public void shutdown() {
    System.err.println("shutdown");
  }
}
Umpa
  • 334
  • 11
  • 16
ewan.chalmers
  • 16,145
  • 43
  • 60
  • 1
    Are `ShutDownHook`s ALWAYS executed? Is it a common and safe practice to rely on those? – Marsellus Wallace Nov 08 '11 at 15:05
  • 2
    @Gevorg As the javadoc says, ShutdownHooks are run by the JVM before exiting when it is terminated normally. If you "kill -9" a Java process, they will not. I have seen shutdown hooks used reliably for orderly shutdown of server processes in commercial enterprise software. – ewan.chalmers Nov 08 '11 at 15:14
  • His problem is getting out of the `accept()` loop into the `finally{}` block, not what to do once he gets there. – user207421 Nov 09 '11 at 01:38
  • @EJP That's partly true - the ShutdownHook provides a way to interrupt socket.accept() on JVM termination, but the current handling of IOException (and by extension SocketException) in the while loop defeats that. However, my answer does not address the finally block at all. The OP was mistaken to think that finally should be run on JVM termination. – ewan.chalmers Nov 09 '11 at 08:35
  • 1
    @sudocode Shutdown hooks are not part of the solution of this problem. He doesn't need to close the socket on termination. The OS will do that for him. His problem is that the finally }{} block isn't executed so he never sees his message, so he *thinks* his socket isn't closed. – user207421 Nov 09 '11 at 09:00
  • @EJP OP stated in his comment that he wants to print a message when "Ctrl+C" is pressed, in which case using a ShutdownHook is addressing one of his problem (though not the main one). – Matthieu Nov 22 '13 at 14:08
  • Shutdown hooks will only work if the program was terminated properly but if i killed the program from sat Task Manager...it wont work – Zuko Aug 31 '15 at 08:36
8

No need in your particular case, the operating system will close all the TCP sockets for you when the program exits.

artbristol
  • 32,010
  • 5
  • 70
  • 103
  • 7
    You're right saying that OS will close all the TCP sockets when the program exits, but I wouldn't say *"No need"* in all cases. It depends if you need to release the listened port before exiting this program (though in this case, it should be OK since the OP wants to close it when program exits) – xav Aug 05 '14 at 12:41
2

From javadoc :

The Java runtime automatically closes the input and output streams, the client socket, and the server socket because they have been created in the try-with-resources statement.

Also

The finalize() method is called by the Java virtual machine (JVM) before the program exits to give the program a chance to clean up and release resources. Multi-threaded programs should close all Files and Sockets they use before exiting so they do not face resource starvation. The call to server.close() in the finalize() method closes the Socket connection used by each thread in this program.

protected void finalize(){
//Objects created in run method are finalized when
//program terminates and thread exits
     try{
        server.close();
    } catch (IOException e) {
        System.out.println("Could not close socket");
        System.exit(-1);
    }
  }
MChaker
  • 2,610
  • 2
  • 22
  • 38
1

Howcome the finally is not run? Probably the while(true) should be replaced with something like

while (!shutdownRequested)

alternatively you can create a shutdown hook that handles the socket close

Peter Szanto
  • 7,568
  • 2
  • 51
  • 53
0

Well, how do you "exit" the program? finally will be executed if an exception will be thrown or if the try block finishes its execution in a "normal" way but I think that might be "hard" because of your while(true).

To close the socket you should use socket.close() and I would recommend you not to rely on the destroy function.

Marsellus Wallace
  • 17,991
  • 25
  • 90
  • 154