2016-03-07 3 views
0

Notebook: http://pastebin.com/hNgjr4QY, код сервера: http://pastebin.com/J5hnz2muПочему ввод из нескольких сокетов не обновляет пользовательский интерфейс правильно? Код

Я в основном interesested в блокнот части кода:

private class ClientHandler implements Runnable 
{ 
    public void run() 
    { 
     String message = null; 

     try { 
      bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

      while ((message = bufferedReader.readLine()) != null) 
      { 
       if (!message.equals("")) 
       { 
        textArea.setText(message); 
        textArea.setCaretPosition(textArea.getDocument().getLength()); 
       } 
      } 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 

и

public void run() 
    { 
     String message = null; 

     try { 
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

      while ((message = bufferedReader.readLine()) != null) 
      { 
       for (ComputerConnections ccc: comCon) 
       { 
        ccc.printWriter.println(message); 
        ccc.printWriter.flush(); 
       } 
      } 
      bufferedReader.close(); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 

хорошо, пункт программы, чтобы позволить так как многие пользователи подключаются, и после того, как они все могут писать в ОДНОМ блокноте, и программа должна обновить его соответствующим образом, ну и кажется, что он ведет себя странно. Сначала он прекрасно обновляется, но затем он просто внезапно останавливается и работает каждые несколько ключевых нажатий!

+0

Вам придется перепроектировать сервер. Если одно соединение получает строку, оно в настоящее время отправляет ее всем подключенным клиентам. Нет ничего, чтобы избежать переключения потока на другое соединение, которое будет читать строку и отправлять ее всем подключенным клиентам. Результат: искаженная и различная последовательность текста для клиентов. – laune

+0

Я не совсем понимаю, я все еще новичок в Java и хватаюсь за воздух ... Как я вижу, клиент должен отправлять серверу, а затем сервер всем доступным клиентам. Но да, это все путается ... Что вы имеете в виду: «Нет ничего, чтобы избежать переключения потока на другое соединение, которое будет читать строку и отправлять ее всем подключенным клиентам». – pigi

ответ

1

Я подозреваю, что это проблема пользовательского интерфейса, а не проблема сокета, которую вы описываете (хотя есть и другие проблемы с этим кодом). Это было бы легко понять, просто поместите некоторые отладочные строки System.out.println() вместо записи пользовательского интерфейса.

Если это так, то вы должны использовать нить EDT так вносить изменения в графический интерфейс, так что единственный поток, который вносит изменения в ГПИ является то, что один и только что один, чтобы избежать помех, как и

SwingUtilities.invokeLater( 
     new Runnable() { 
      public void run() { 
       textArea.setText(message); 
      } 
     } 
    ); 

Пользовательским интерфейсам значительно сложно сделать многопоточность, поэтому наилучшим способом этого является очередь обновлений, которые обрабатываются одним потоком пользовательского интерфейса (в случае Javas, EDT - Event Dispatch Thread).

+1

Эта проблема нитей хуже, потому что более ранняя документация документации setText о том, что она была потокобезопасной, но позже была удалена, потому что она никогда не была поточно-безопасной. Это обычная ошибка для людей, которые изучали Java в прошлом. – Ferrybig

+1

Хорошая идея, но вы можете создать много объектов. Один для каждого обновления сокета, поэтому, IMHO, SwingWorker будет лучше подходить. – Ayman

+0

'SwingWorker' обычно используется в фоновых задачах, чтобы избежать замораживания пользовательского интерфейса. Обновления пользовательского интерфейса обычно должны отправляться на EDT, для которого используется SwingUtilities.invokeLater(). Единственная причина, по которой я буду использовать SwingWorker в этом случае, - это то, что я периодически буферизую вход и периодически обновляю пользовательский интерфейс. –

0

Я бы использовал SwingWorker для такого вида обработки.

Позвольте всем сокетам publish данных, а затем обновите GUI в методе process.