ServerSocket卡在accept的时候怎么正确关闭

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ServerSocket卡在accept的时候怎么正确关闭相关的知识,希望对你有一定的参考价值。

加入一个ServerSocket正在另一个线程堵塞accept,那如何停止accept或者关闭Socket?

Server socket 设置下超时
setSoTimeout
然后在Listen线程中用interrupt

其实直接close socket也可以,不过会抛出异常,我的意思是有什么比较安全而又简单的办法?难道要加一个标志,然后要关闭的时候把标志设为stop,然后连接listernSocket?这样也未免太麻烦了

JDK5.0里面新增了Java.util.concurrent包(对于多线程的开发建议尽量使用这个包),下面是javadoc里面的样例代码

用法示例
下面给出了一个网络服务的简单结构,这里线程池中的线程作为传入的请求。它使用了预先配置的 Executors.newFixedThreadPool(int) 工厂方法:

java 代码

class NetworkService implements Runnable
private final ServerSocket serverSocket;
private final ExecutorService pool;

public NetworkService(int port, int poolSize)
throws IOException
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);


public void run() // run the service
try
for (;;)
pool.execute(new Handler(serverSocket.accept()));

catch (IOException ex)
pool.shutdown();




class Handler implements Runnable
private final Socket socket;
Handler(Socket socket) this.socket = socket;
public void run()
// read and service request on socket



下列方法分两个阶段关闭 ExecutorService。第一阶段调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消所有遗留的任务:

java 代码

void shutdownAndAwaitTermination(ExecutorService pool)
pool.shutdown(); // Disable new tasks from being submitted
try
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");

catch (InterruptedException ie)
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();



内存一致性效果:线程中向 ExecutorService 提交 Runnable 或 Callable 任务之前的操作 happen-before 由该任务所提取的所有操作,后者依次 happen-before 通过 Future.get() 获取的结果。
参考技术A serverSocket会一直接受连接,直到running设为false。
但问题是如果我程序要退出了,就算把running设为false,accept也会卡在那里,所以必须再接受一次连接程序才能退出。
如果我退出时直接关闭ServerSocket比如serverSocket.close(),那么程序是可以马上结束,但是accept会抛异常,结果就是每次结束程序都有异常。

ServerSocket类的常用方法

1.accept:侦听并接受此套接字的连接;此方法在连接传入之前一直阻塞。

2.setSoTimeout(timeout)方法的作用时设置超时时间,通过指定超时timeout值启用/禁用超时功能,以ms为单位。

  必须在进入阻塞前调用这个方法,才能生效,一旦超时,程序会触发SocketTimeoutException异常;默认值是0即永远等待。

 

Server.java

package com.company.s7;

import java.io.IOException;
import java.net.ServerSocket;

public class Server 
    public static void main(String[] args) 
        try 
            ServerSocket serverSocket=new ServerSocket(8000);
            System.out.println(serverSocket.getSoTimeout());
            serverSocket.setSoTimeout(4000);
            System.out.println(serverSocket.getSoTimeout());
            System.out.println();

            System.out.println("begin "+System.currentTimeMillis());
            serverSocket.accept();
            System.out.println(" end "+System.currentTimeMillis());
        catch (IOException e)
            e.printStackTrace();
        
    

Client.java

package com.company.s7;

import java.io.IOException;
import java.net.Socket;

public class Client 
    public static void main(String[] args) 
        try 
            System.out.println("client begin "+System.currentTimeMillis());
            Socket socket=new Socket("localhost",8000);
            System.out.println("client end "+System.currentTimeMillis());
        catch (IOException e)
            e.printStackTrace();
            System.out.println("catch "+System.currentTimeMillis());
        
    

 

backlog参数含义:

技术图片

允许接受客户端连接请求的个数。

如果队列已满,则拒接该连接。

blacklog参数如果小于等于0,则使用默认值50;

以上是关于ServerSocket卡在accept的时候怎么正确关闭的主要内容,如果未能解决你的问题,请参考以下文章

Java - 如何检查 ServerSocket.accept() 是不是连接?

如何中断 ServerSocket accept() 方法?

ServerSocket对象调用accept()方法返回一个啥类型的对象?

网络I/O模型--03非阻塞模式(ServerSocket与Socket的超时处理)--解除accept() read()方法阻塞

java中用serverSocket类如何向指定IP的客户端发送数据

java实现聊天室是怎么做到的?