之前的代码中关闭了 socket 对象的输入流与输出流,但并没有关闭掉socket 对象,会造成服务器资源的浪费,应通过调用 socket 的 close() 方法来关闭当前的socket 对象。
因此,可以通过创建一个 ServerScanThread 线程,使其一直在后台运行,扫描看哪些 socket 对象的 Input Stream 与 OutputStream 均已关闭,当扫描到当前 socket 对象的输入输出流均已关闭,则关闭当前 socket 对象。
扫描线程代码:
public class ServerScanThread extends Thread { public static List<Socket> socketList = new LinkedList<Socket>(); //实例化一个静态列表,使其存放 Socket,使用LinkedList 便于删除 public ServerScanThread(){ setDaemon(true);//设置为后台线程 start(); } public void run(){ while(true){ //1.我要去扫描整个集合,如果当前集合是空的,我就去睡觉去喽 while(socketList == null ||socketList.size()<= 0){ System.out.println("这会儿集合里没有socket,我先睡觉10s");//测试代码 try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //2.如果运行到这里,则说明 socketList 中有元素,则有开始扫描判断其socket 对象是否已经关闭了其输入流和输入流。 for(int i = 0;i<socketList.size();i++){ Socket socket = socketList.get(i);//从socketList 集合中获得一个 socket 对象。 if(socket.isInputShutdown() & socket.isOutputShutdown()){ try { socket.close();//关闭当前 socket 对象 socketList.remove(i);//从当前列表中移除当前 socket 对象。 System.out.println("有一个 socket 被关闭了");//测试代码 //i--; LinkedList在移除掉一个元素后,其后边的元素下标统统会减一,为保证不会跳过某一个元素,可在此处将 i 自减,也可以不因为会进行再次扫描 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } try {
Thread.sleep(5000);//扫描完一遍之后休息五秒钟 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }//整个线程完成后可以在 Server 中进行调用。 } }
服务器端代码:
public class Server1 { public static void main(String[] args) { Scanner input = new Scanner(System.in); try { @SuppressWarnings("resource") ServerSocket server = new ServerSocket(9880); new ServerScanThread(); while (true){ Socket client = server.accept(); ServerScanThread.socketList.add(client);//在 socketList 集合中加入 socket 实例对象 System.out.println("来自"+ client.getInetAddress().getHostAddress()+"的客户端已连接成功!"); if(client != null){ //开始对话 new WriterThread("服务端",client); new ReaderThread("服务端",client); } } } catch (IOException e) { e.printStackTrace(); } input.close(); } }
- 当没有客户端运行时的输出:
此时没有socket对象,程序不停在内部的第一个while 循环里运行,每隔十秒打印一次。
- 当运行客户端但不关闭socket 的输入输出流时的输出:
由于是先运行的服务器端,所以while 循环先会执行一次,这次循环中还没有socket 对象,当客户端开始运行时,由于没有输入 byebye ,所以不会关闭 socket 的输入流与输出流,程序会执行到内部 for 循环不断循环。
- 当运行客户端并且关闭socket 的输入输出流时的输出:
在两端分别输入 byebye 关闭输入输出流之后,当前socket被扫描出来并关闭。因为设置的该扫描线程为一个后台线程,当 Server 停止运行时,该线程也停止。
如有不对之处,还望指正,谢谢(●'◡'●)