如何以正确的方式关闭插座?

时间:2011-11-08 14:24:26

标签: java sockets tcp

这是一个简单的TCP服务器。程序终止后如何关闭套接字? 我使用try / finally并尝试关闭套接字。但是当我退出程序时它不会运行finally块。

任何人都可以知道如何以正确的方式关闭套接字?

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!");
    }

5 个答案:

答案 0 :(得分:12)

创建ServerSocket后,您可以添加ShutdownHook以在JVM终止时关闭它,如下所示:

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

调用ServerSocket#close将终止阻塞ServerSocket.accept调用,导致它抛出SocketException。但是,请注意,您在while循环中当前对IOException的处理意味着您将重新进入while循环以尝试在已关闭的套接字上接受。 JVM仍将终止,但它有点不整洁。

如果在Eclipse中终止控制台应用程序(至少在Windows上),则不会运行关闭挂钩。但是如果您在普通控制台中使用CTRL-C Java,它们就会运行。要让它们运行,您需要正常终止JVM,例如SIGINT或SIGTERM而不是SIGKILL(kill -9)。

您可以在Eclipse或控制台中执行的简单程序将证明这一点。

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");
  }
}

答案 1 :(得分:7)

在您的特定情况下,操作系统不会在程序退出时关闭所有TCP套接字。

答案 2 :(得分:2)

来自javadoc

  

Java运行时自动关闭输入和输出流,   客户端套接字和服务器套接字,因为它们已经存在   在try-with-resources语句中创建。

另外

  

Java虚拟机(finalize())调用JVM方法   在程序退出之前给程序一个清理的机会   释放资源。多线程程序应关闭所有文件和   他们在退出之前使用的套接字,因此他们不会面对资源   饥饿。 server.close()方法中对finalize()的调用结束   此程序中每个线程使用的Socket连接。

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);
    }
  }

答案 3 :(得分:1)

结果终于没有运行?可能会将while(true)替换为

之类的东西
while (!shutdownRequested)

或者你可以创建一个处理套接字关闭的关闭钩子

答案 4 :(得分:0)

那么,你如何“退出”该计划?如果将抛出异常或者try块以“正常”方式完成执行,则会执行finally但我认为由于while(true)而可能会“很难”。

要关闭套接字,您应该使用socket.close(),我建议您不要依赖销毁功能。