之前的代碼中關閉了 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 循環裡運行,每隔十秒打印一次。
由於是先運行的服務器端,所以while 循環先會執行一次,這次循環中還沒有socket 對象,當客戶端開始運行時,由於沒有輸入 byebye ,所以不會關閉 socket 的輸入流與輸出流,程序會執行到內部 for 循環不斷循環。
在兩端分別輸入 byebye 關閉輸入輸出流之後,當前socket被掃描出來並關閉。因為設置的該掃描線程為一個後台線程,當 Server 停止運行時,該線程也停止。
如有不對之處,還望指正,謝謝(●'◡'●)