2013-09-27 105 views
0

我做了一個我希望我的程序是什麼的例子。問題是我不能讓我的套接字連接正常工作(我希望它工作的方式)。我不知道問題出在哪裏。Java Socket凍結問題

public class TestChat extends Frame { 

public static Panel1 p1; 
public static Panel2 p2; 
public static TestChat tc; 

public TestChat() { 
    super(); 
    setPreferredSize(new Dimension(800, 600)); 
    setLayout(new BorderLayout()); 
    addWindowListener(new WindowAdapter() { 
     public void windowClosing(WindowEvent we) { 
      System.exit(0); 
     } 
    }); 

    p1 = new Panel1(); 
    p2 = new Panel2(); 
    add(p1); 
} 

public static void main(String[] args) { 
    // TODO code application logic here 
    tc = new TestChat(); 
    tc.pack(); 
    tc.setVisible(true); 
    ///* 
    try { 
     TestChat.p2.run(); 
    } catch (IOException ioe) { 
     System.out.println("IO here"); 
    } 
    //*/ 
} 

public void change(int to) { 
    if (to == 1) { 
     tc.remove(p2); 
     tc.add(p1); 
    } 
    if (to == 2) { 
     tc.remove(p1); 
     tc.add(p2); 
    } 
    tc.pack(); 
} 
} 

public class Panel1 extends Panel implements ActionListener{ 

public Button button = new Button("Launch chat"); 

public Panel1() { 
    super(); 
    setLayout(new BorderLayout()); 
    Label label = new Label("Launcher panel here"); 
    add(label); 
    add(button, BorderLayout.SOUTH); 
    button.addActionListener(this); 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    if (e.getSource() == button) { 
     TestChat.tc.change(2); 
     /* 
     try { 
      TestChat.p2.run(); 
     } catch (IOException ioe) { 
      System.out.println("IO here"); 
     } 
     //*/ 
    } 
} 

} 

public class Panel2 extends Panel implements ActionListener { 

private static final int LOGIN_MAX = 300; 
public static TextArea ta = new TextArea(); 
public static TextField tf = new TextField(); 
public static TextArea logins = new TextArea(); 
public static PrintWriter out = null; 
public static String[] loginList = new String[LOGIN_MAX]; 
public static int loginCount = 0; 
public Panel temp = new Panel(); 
public Button startButton = new Button("Start!"); 
///* 
public String fromServer; 
public BufferedReader in = null; 
public BufferedReader stdIn; 
public Socket kkSocket = null; 
//*/ 

public Panel2() { 
    setLayout(new BorderLayout()); 
    temp.setLayout(new BorderLayout()); 
    ta.setEditable(false); 
    tf.addActionListener(this); 
    startButton.addActionListener(this); 
    logins.setEditable(false); 
    temp.add(ta, BorderLayout.CENTER); 
    temp.add(tf, BorderLayout.SOUTH); 
    add(temp); 
    add(logins, BorderLayout.EAST); 
    add(startButton, BorderLayout.SOUTH); 
} 

//private static void makeLogins() { 
public static void makeLogins() { 
    String userArea = loginList[0] + "\n"; 
    for (int i = 1; i < loginCount; i++) { 
     userArea = userArea + loginList[i] + "\n"; 
    } 
    logins.setText(userArea); 
} 

public void run() throws IOException { 

    kkSocket = null; 

    BufferedReader in = null; 

    try { 
     kkSocket = new Socket("localhost", 4444); 
     out = new PrintWriter(kkSocket.getOutputStream(), true); 
     in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream())); 
    } catch (UnknownHostException e) { 
     //System.err.println("Can't host to server."); 
     System.out.println("Can't host to server."); 
     System.exit(1); 
    } catch (IOException e) { 
     System.err.println("Couldn't get I/O for the connection to server."); 
     System.exit(1); 
    } 

    BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); 
    String fromServer; 

    while ((fromServer = in.readLine()) != null) { 
     validate(); 
     if (fromServer.startsWith("cmd_newUser_")) { 
      loginList[loginCount++] = fromServer.substring(12); 
      if (loginCount > 1) { 
       Arrays.sort(loginList, 1, loginCount - 1); 
      } 
      makeLogins(); 
     } else if (fromServer.startsWith("cmd_deleteUser_")) { 
      String tmp = fromServer.substring(15); 
      for (int i = 0; i < loginCount; i++) { 
       if (loginList[i].equals(tmp)) { 
        loginList[i] = "" + ((char) 255); 
        break; 
       } 
      } 
      Arrays.sort(loginList, 1, loginCount); 
      loginCount--; 
      makeLogins(); 
     } else { 
      ta.append(fromServer + "\n"); 
     } 
     if (fromServer.equals("Bye.")) { 
      break; 
     } 
    } 

    out.close(); 
    in.close(); 
    stdIn.close(); 
} 

private void sendStr(PrintWriter out) { 
    if (tf.getText() != "") { 
     out.println(tf.getText()); 
     tf.setText(""); 
    } 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    if (e.getSource() == tf) { 
     sendStr(out); 
    } else if (e.getSource() == startButton) { 
     System.out.println("I make some actions in the original proj"); 
    } 
} 
} 

當我用這種方式,然後我的程序連接,一切工作正常。但是當按下按鈕時(註釋調用),我想從Panel1類開始連接。當我嘗試從Panel1調用它時,我的整個程序都凍結了。問題在哪裏,我該如何解決?

P.S.這裏是我的服務器代碼(以防萬一)

public class KKMultiServer extends Frame { 

public static int userCount = 0; 
public static Label users; 
public static KKMultiServerThread[] userList=new KKMultiServerThread[100]; 
public static int writer=0; 
public static int curNum=1; 

public KKMultiServer() { 
    super("Server"); 
    setLayout(new GridLayout(2, 1)); 
    users = new Label("Users online: " + userCount); 
    add(users); 
    setLocation(200, 200); 
    setResizable(false); 
    setMinimumSize(new Dimension(300, 200)); 
    addWindowListener(new WindowAdapter() { 
     public void windowClosing(WindowEvent we) { 
      System.exit(0); 
     } 
    }); 
} 

public static void main(String[] args) throws IOException { 
    ServerSocket serverSocket = null; 
    boolean listening = true; 
    KKMultiServer server = new KKMultiServer(); 
    server.pack(); 
    server.setVisible(true); 

    try { 
     serverSocket = new ServerSocket(4444); 
    } catch (IOException e) { 
     System.err.println("Could not listen on port: 4444."); 
     System.exit(-1); 
    } 

    while (listening) {        
     userList[writer]=new KKMultiServerThread(serverSocket.accept()); 
     System.out.println("Client added!"); 
     userCount++; 
     users.setText("Users online: " + userCount); 
     userList[writer++].start();   


    } 

    serverSocket.close(); 
} 
} 
+1

剛開始的時候,'static'不是你的朋友。要非常小心地聲明'static'變量,如果你不小心,他們會回來咬你...只是說 – MadProgrammer

+1

現在我有太多的代碼要排序,但我懷疑是你試圖運行您在事件調度線程上的套接字代碼。 – chrylis

+0

@chrylis Spot on ... – MadProgrammer

回答

1
  1. 以這種方式使用static引用是一個非常糟糕的設計。你冒着不知道你所指的是什麼的風險。
  2. Swing是單線程環境,也就是說,所有與UI的交互和修改都需要在Event Dispatching Thread的上下文中執行。阻塞此線程的任何操作(如阻塞I/O或長時間運行的循環)將阻止UI處理新事件並繪製請求。

到目前爲止,你基本上已經把它儲存起來了。當main由JVM運行時,它正在運行,通常稱爲「主」線程。當您開始使用任何Swing組件時,Swing API將啓動「事件調度線程」...

所以發生了什麼,您正在啓動您的應用程序的UI部分,它的上下文正在移動到EDT,而run方法p2繼續在main線程中運行。

現在你要開始按鈕通訊科,你感動的執行上下文的EDT,這使它看起來像你程序已經掛起....

現在,你有兩個問題。首先,您需要將通訊從EDT中刪除,其次是,您不應該從EDT以外的任何線程修改或更新UI ...

有許多解決方案可用於你,SwingWorker可能會是你的問題最簡單的。

看看Concurrency in Swing瞭解更多詳情