之前的代碼中關閉了 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 停止運行時,該線程也停止。
如有不對之處,還望指正,謝謝(●'◡'●)