java Socket程式設計呼叫ServerSocket的close方法
阿新 • • 發佈:2018-11-12
做一個簡單的聊天系統伺服器
伺服器中有一個輸入埠的控制元件,兩個JButton按鈕“停止”和“執行”
點選“執行”按鈕,啟動伺服器
點選“停止”按鈕,呼叫ServerSocket的close方法,停止伺服器。
上部分程式碼:
btn_ok.setText("執行"); btn_ok.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { String strPort = port.getText().trim(); try { serverSocket = new ServerSocket(Integer.parseInt(strPort)); System.out.println("伺服器已啟動"); btn_ok.setEnabled(false); } catch (NumberFormatException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } //訊息分發 new Thread(new MsgRunnable()).start(); }
btn_quit.setText("停止"); btn_quit.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { try { if(serverSocket!=null){ serverSocket.close(); isRun = false; btn_ok.setEnabled(true); } else{ JOptionPane.showMessageDialog(null, "服務還未啟動,請啟動服務再停止"); } } catch (IOException e1) { e1.printStackTrace(); } } });
class MsgRunnable implements Runnable{ @Override public void run() { while(true){ try { if(!serverSocket.close()){ Socket socket = serverSocket.accept(); System.out.println("伺服器正在監聽"); ClientPro cp = new ClientPro(socket); cp.start(); addConnetion(socket, cp); } else{ JOptionPane.showMessageDialog(null, "伺服器已關閉"); return; } } catch (IOException e1) { e1.printStackTrace(); } } } }
根據我的想法,點選“停止”時,serverSocket關閉,那麼 分發執行緒中的if(!serverSocket.close())會執行判斷,彈出伺服器已關閉對話方塊,看起來好像挺符合程式碼的邏輯的。
但是實際執行時,卻報Socket close異常。
於是各種除錯,終於發現異常是分發執行緒的e1.printStackTrace();
但為什麼會報異常呢?
因為ServerSocket的accept方法是個當前執行緒阻塞方法,當它只有接受一個客戶端連結時,才會往下執行,我們啟動伺服器後,進入serverSocket.accept方法
它就一直在等待客戶端的連結,所以它雖然是個無限迴圈執行緒,但判定條件卻是多餘的(當然,前提是你沒進入accept方法)。
這時突然我們的另一個執行緒將serverSocket關閉了,那麼看下我們accept方法的原始碼:
public Socket accept() throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!isBound())
throw new SocketException("Socket is not bound yet");
Socket s = new Socket((SocketImpl) null);
implAccept(s);
return s;
}
所以異常就產生了
這本來是個很簡單的問題,但卻困擾了好一會.........