2013-09-27 2 views
0

Я сделал пример того, что хочу, чтобы моя программа была. Проблема в том, что я не могу заставить мое подключение сокета работать правильно (как я хочу, чтобы он работал). И я не знаю, где проблема здесь.Проблема с замораживанием Java-сокета

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

Слишком много кода для меня, чтобы сортировать прямо сейчас, но мое подозрение в том, что вы пытаетесь запустить ваш код сокета в Thread Dispatch Thread. – chrylis

+0

@chrylis Spot on ... – MadProgrammer

ответ

1
  1. Использование static ссылки таким образом очень плохой дизайн. Вы рискуете не знать точно, на что ссылаетесь.
  2. Swing - это однопоточная среда, то есть ожидается, что все взаимодействия и модификации пользовательского интерфейса будут выполняться из контекста Диспетчерского потока событий. Любые операции, которые блокируют этот поток, например, блокирование ввода-вывода или длинных циклов, не позволяют пользовательскому интерфейсу обрабатывать новые события и запросы на рисование.

В настоящее время вы до сих пор не понимаете этого. Когда main управляется JVM, он запускается, что обычно называется «основной» нитью. Когда вы начнете использовать какой-либо компонент Swing, Swing API запустит «Event Dispatching Thread» ...

Итак, что происходит, вы запускаете часть своего пользовательского интерфейса, его контекст переносится на EDT, тогда как метод runp2 продолжает работать в потоке main.

Теперь, когда вы хотите, чтобы начать с коммами кнопки, вы переместили контекст выполнения в EDT, который делает его похожим на вас приложения повисли ....

Теперь у вас есть два проблемы. Во-первых, вам нужно получить свои сообщения от EDT, во-вторых, вы никогда не должны изменять или обновлять пользовательский интерфейс из любого потока, отличного от EDT ...

Существует ряд решений, которые доступны для вы, SwingWorker, вероятно, будет самым простым для вашей проблемы.

Взгляните на Concurrency in Swing для более подробной информации

Смежные вопросы