1. 程式人生 > >java Socket程式設計呼叫ServerSocket的close方法

java Socket程式設計呼叫ServerSocket的close方法

做一個簡單的聊天系統伺服器

伺服器中有一個輸入埠的控制元件,兩個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;
    }


所以異常就產生了

這本來是個很簡單的問題,但卻困擾了好一會.........