2013-03-27 44 views
0

當我學習java套接字時,我已經在兩個框架中進行了功能性但非常簡單的聊天:一個客戶端和一個服務器。該應用程序只是本地和工作。但是,當我關閉窗口時它不會停止(儘管我將WindowListener添加到兩個框架類中):出現了什麼問題?爲什麼這個客戶端/服務器程序不會停止?

不要忘記首先運行服務器,然後運行客戶端:只有在客戶端連接之後,兩個框架纔會顯示。

這裏是SimpleSocketFrame.java(對於兩個幀基類):

package com.loloof64.java_se.simple_socket; 

import java.awt.GridLayout; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 

import javax.swing.JFrame; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 

public abstract class SimpleSocketFrame extends JFrame { 

    public SimpleSocketFrame() { 
     setTitle(getFrameTitle()); 
     setLayout(new GridLayout(0, 1)); 

     messageToAddField = new JTextField(30); 
    messageToAddField.addKeyListener(new KeyAdapter() { 

      @Override 
      public void keyReleased(KeyEvent e) { 
       if (e.getKeyCode() == KeyEvent.VK_ENTER){ 
        if (! messageToAddField.getText().isEmpty()) { 
         addMessage(messageToAddField.getText()); 
         messageToAddField.setText(""); 
        } 
       } 
      } 

    }); 

     printedMessagesArea = new JTextArea(10,30); 
     printedMessagesArea.setEditable(false); 

     add(messageToAddField); 
     add(printedMessagesArea); 

    pack(); 
} 

protected abstract void addMessage(String s); 
protected abstract String getFrameTitle(); 

private static final long serialVersionUID = -5861605385948623162L; 
protected JTextArea printedMessagesArea; 
private JTextField messageToAddField; 

} 

這裏是服務器應用程序類:SimpleSocketServer.java

package com.loloof64.java_se.simple_socket; 

import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintStream; 
import java.net.ServerSocket; 
import java.net.Socket; 

import javax.swing.JOptionPane; 

public class SimpleSocketServer extends SimpleSocketFrame { 

    public SimpleSocketServer(){ 
     super(); 
     setTitle("Simple Server"); 
     try { 
      serverSocket = new ServerSocket(12345); 
      relatedSocket = serverSocket.accept(); 

      outStream = new PrintStream(relatedSocket.getOutputStream()); 
      isr = new InputStreamReader(relatedSocket.getInputStream()); 
      inStream = new BufferedReader(isr); 

      final InStreamRunnable inStreamRunnable = new InStreamRunnable(); 
      Thread inStreamReaderThread = new Thread(inStreamRunnable); 



      addWindowListener(new WindowAdapter() { 

       @Override 
       public void windowClosing(WindowEvent evt) { 
        try { 
         inStream.close(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
        try { 
        isr.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
        outStream.close(); 
       try { 
        relatedSocket.close(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       try { 
        serverSocket.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
        inStreamRunnable.stop(); 
        System.exit(0); 
       } 

      }); 

      inStreamReaderThread.start(); 
     } catch (IOException e) { 
      JOptionPane.showMessageDialog(this, "Could not create the server !!!", 
        "Fatal error", JOptionPane.ERROR_MESSAGE); 
      System.exit(1); 
      e.printStackTrace(); 
     } 
    } 

    private class InStreamRunnable implements Runnable { 

     @Override 
     public void run() { 
      while (weMustGoOn){ 
       String line; 
       try { 
        line = inStream.readLine(); 
            printedMessagesArea.setText(printedMessagesArea.getText()+line+"\n"); 
       } catch (IOException e) { 

       } 
      } 
    } 

     public void stop(){ 
      weMustGoOn = false; 
     } 

     private boolean weMustGoOn = true; 

    } 

    @Override 
    protected void addMessage(String s) { 
     s = "Serveur> "+s; 
     outStream.println(s); 
     printedMessagesArea.setText(printedMessagesArea.getText()+"Client> "+s+"\n"); 
    } 

    @Override 
    protected String getFrameTitle() { 
     return "Simple Server"; 
    } 

    public static void main(String[] args) { 
     new SimpleSocketServer().setVisible(true); 
    } 

    private static final long serialVersionUID = 4288994465786972478L; 
    private Socket relatedSocket; 
    private ServerSocket serverSocket; 
    private PrintStream outStream; 
    private InputStreamReader isr; 
    private BufferedReader inStream; 
} 

這裏是客戶端類:SimpleSocketClient.java

package com.loloof64.java_se.simple_socket; 

import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintStream; 
import java.net.InetAddress; 
import java.net.Socket; 

import javax.swing.JOptionPane; 

public class SimpleSocketClient extends SimpleSocketFrame { 

    public SimpleSocketClient(){ 
     try { 
      socket = new Socket(InetAddress.getLocalHost(), 12345); 
      outStream = new PrintStream(socket.getOutputStream()); 

     isr = new InputStreamReader(socket.getInputStream()); 
      inStream = new BufferedReader(isr); 

      final InStreamRunnable inStreamRunnable = new InStreamRunnable(); 
     Thread inStreamReaderThread = new Thread(inStreamRunnable); 

      addWindowListener(new WindowAdapter() { 

       @Override 
       public void windowClosing(WindowEvent evt) { 
       try { 
         inStream.close(); 
       } catch (IOException e2) { 
        e2.printStackTrace(); 
       } 
       try { 
        isr.close(); 
       } catch (IOException e1) { 
         e1.printStackTrace(); 
        } 
       outStream.close(); 
       try { 
        socket.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
       inStreamRunnable.stop(); 
       System.exit(0); 
      } 

     }); 
      inStreamReaderThread.start(); 
    } catch (IOException e) { 
      JOptionPane.showMessageDialog(this, "Could not create the client !!!", 
        "Fatal error", JOptionPane.ERROR_MESSAGE); 
      System.exit(1); 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) { 
     new SimpleSocketClient().setVisible(true); 
    } 

private class InStreamRunnable implements Runnable { 

    @Override 
    public void run() { 
      while (weMustGoOn){ 
      String line; 
      try { 
       line = inStream.readLine(); 
         printedMessagesArea.setText(printedMessagesArea.getText()+line+"\n"); 
       } catch (IOException e) { 

       } 
      } 
     } 

    public void stop(){ 
     weMustGoOn = false; 
    } 

    private boolean weMustGoOn = true; 

    } 

@Override 
protected void addMessage(String s) { 
    s = "Client> "+s; 
    outStream.println(s); 
    printedMessagesArea.setText(printedMessagesArea.getText()+s+"\n"); 
} 

@Override 
    protected String getFrameTitle() { 
    return "Simple Client"; 
} 

    private static final long serialVersionUID = 5468568598525947366L; 
    private Socket socket; 
    private PrintStream outStream; 
    private InputStreamReader isr; 
    private BufferedReader inStream; 


} 
+0

這對於客戶端和服務器都是一樣的問題嗎? – Austin 2013-03-27 23:58:20

+0

是的,兩個框架都不能關閉。 – loloof64 2013-03-27 23:59:28

+0

運行守護程序線程時,系統不會退出 – MadProgrammer 2013-03-28 02:42:01

回答

2

當您試圖關閉網絡輸入Readers時,程序不會停止,因爲它將關閉無限期阻止的JFrameBufferedReaderInputStreamReader對象不能關閉作爲客戶端線程被阻塞在該readLine呼叫被從服務器等待響應

line = inStream.readLine(); 

註釋掉或刪除:

inStream.close(); 

isr.close(); 

只需關閉Socket即可。

Aside:與多線程網絡應用程序的Swing組件進行交互時,請始終使用SwingWorkerSwingWorkers旨在與Swing組件正確交互。

+0

這是工作。另外,我將用SwingWorkers替換簡單的線程。 – loloof64 2013-03-28 08:07:29

+0

此外,它是否僅僅意味着當我調用isr.close()時,我正在等待查找不可用的鎖? – loloof64 2013-03-28 11:39:48

+0

相反,您正在等待'close'中的'Reader'中的鎖「信號量」,因爲您正在等待來自客戶端/服務器的響應,所以從未收到通知。如此有效,這是一個僵局。 – Reimeus 2013-03-28 11:54:46

2

您應該在後添加finally塊和catch關閉套接字,然後您可以通過系統退出方法關閉您的程序。

+0

是的,您是對的:我在計算機的代碼上添加了最後的子句。 – loloof64 2013-03-28 08:08:27

相關問題