2012-06-25 216 views
4

我使用套接字編寫Java客戶端/服務器的GUI應用程序,現在的問題是:的Java Swing GUI凍結

我有一個按鈕,啓動監聽指定端口:

按鈕actionPerformed方法

private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {            
    int port = Integer.parseInt(portTextfield.getText(), 10); 

    try { 
     socket.listen(port); 
    } catch (IOException ex) { 
    } 
} 

這裏是socket.listen方法

public static void listen() throws IOException { 
    ServerSocket ss = new ServerSocket(port); 

    while (true) 
     new socket(ss.accept()); 
} 

「插座」 CL屁股擴展「線程」
所以在ss.accept()返回一個值後,它會在單獨的線程中創建新的套接字實例。

點擊按鈕後,GUI會凍結,因爲在socket.listen方法中存在無限循環。我怎樣才能避免這種情況?

+0

和你的問題吧。 ..,爲更好的幫助,儘早發佈SSCCE – mKorbel

+1

閱讀[擺動中的併發](http://docs.oracle.com/javase/tutor IAL/uiswing /併發/)。 – assylias

+0

僅供參考,有一個工作示例[此處](http://stackoverflow.com/a/3245805/230513)。 – trashgod

回答

5

你在你的設計中的兩個缺陷:

  1. ss.accept()是一個阻塞調用,這樣你的用戶界面將凍結,直到有傳入連接
  2. 從不運行while(true)在EDT中循環。

而是做到以下幾點:

  • 當按鈕被點擊創建一個線程,該線程將開始偵聽傳入連接。
  • 每當有傳入連接時,創建另一個線程將採取傳入的客戶端連接並處理它。
3

您將需要使用多線程。如果我在哪裏,我會分開GUI代碼和服務器代碼,並且當按下按鈕時,我只需將Server代碼作爲新線程啓動。

你的代碼凍結了GUI,基本上是因爲所有事件都是在事件調度線程(EDT)上執行的,它是處理所有GUI事件和相應事件的線程。如果你阻止它,阻止它或者投入循環,它會影響它的性能。

3

檢查了這一點:http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html

1)如果你正在編寫GUI應用程序可能會在Swing永遠不會調用 在事件調度線程或事件處理程序阻止方法。 例如,如果您正在閱讀文件或打開網絡連接 單擊按鈕時,不要在actionPerformed()方法上執行該操作,而應該創建另一個工作線程來執行該任務,並從actionPerformed()返回 。這會保持GUI的響應,但是如果操作是需要 用戶等待的事情,則它又取決於設計,而不是考慮使用invokeAndWait()來同步 更新。

使用多線程:http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html

5

只要你

new socket(ss.accept()); 

立即返回,你只需要改變你的

while (true) 

,這把EDT(事件指派線程)進入一個無限循環,你的GUI變得irresponsive。所以,刪除這一行。

如果您不能再使用SwingWorker類(http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List) 創建擴展SwingWorker的嵌套類。只需撥打swingWoker.execute();(在創建它的對象後)在你的listenButtonActionPerformed(java.awt.event.ActionEvent evt)方法中。

參見教程:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

從不創建一個新的線程,並從擺動運行EDT

2

嘗試這些...

1. During getting the initial connection delay can occur, so first create and emptysocket,then try to connect to the server.

`Socket s = new Socket();` 

    `s.connect(new InetSocketAddress("ip_addr",port_nos),1000);` 

2. And Secondly always keep the Non-UI work out of Your UI thread..

這裏是我的服務器的實例 - 客戶端通信..

客戶端代碼:

public class ClientWala { 

    public static void main(String[] args) throws Exception{ 

     Boolean b = true; 
    Socket s = new Socket(); 
    s.connect(new InetSocketAddress("127.0.0.1", 4444),1000); 

    System.out.println("connected: "+s.isConnected()); 


    OutputStream output = s.getOutputStream(); 
    PrintWriter pw = new PrintWriter(output,true); 

    // to write data to server 
    while(b){ 

     if (!b){ 

      System.exit(0); 
     } 

     else { 
      pw.write(new Scanner(System.in).nextLine()); 
     } 
    } 


    // to read data from server 
    InputStream input = s.getInputStream(); 
    InputStreamReader isr = new InputStreamReader(input); 
    BufferedReader br = new BufferedReader(isr); 
    String data = null; 

    while ((data = br.readLine())!=null){ 

     // Print it using sysout, or do whatever you want with the incoming data from server 

    } 




    } 
} 

服務器端代碼:

import java.io.* 
import java.net.*; 


public class ServerTest { 

    ServerSocket s; 

    public void go() { 

     try { 
      s = new ServerSocket(44457); 

      while (true) { 

       Socket incoming = s.accept(); 
       Thread t = new Thread(new MyCon(incoming)); 
       t.start(); 
      } 
     } catch (IOException e) { 

      e.printStackTrace(); 
     } 

    } 

    class MyCon implements Runnable { 

     Socket incoming; 

     public MyCon(Socket incoming) { 

      this.incoming = incoming; 
     } 

     @Override 
     public void run() { 

      try { 
       PrintWriter pw = new PrintWriter(incoming.getOutputStream(), 
         true); 
       InputStreamReader isr = new InputStreamReader(
         incoming.getInputStream()); 
       BufferedReader br = new BufferedReader(isr); 
       String inp = null; 

       boolean isDone = true; 

       System.out.println("TYPE : BYE"); 
       System.out.println(); 
       while (isDone && ((inp = br.readLine()) != null)) { 

        System.out.println(inp); 
        if (inp.trim().equals("BYE")) { 
         System.out 
           .println("THANKS FOR CONNECTING...Bye for now"); 
         isDone = false; 
         s.close(); 
        } 

       } 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       try { 
        s.close(); 
       } catch (IOException e1) { 
        // TODO Auto-generated catch block 
        e1.printStackTrace(); 
       } 
       e.printStackTrace(); 
      } 

     } 

    } 

    public static void main(String[] args) { 

     new ServerTest().go(); 

    } 

}