Серверное приложение зависает при программировании сокетов Java - PullRequest
0 голосов
/ 30 мая 2018

Мое приложение продолжает загружаться (курсор в виде круга).Вот мой код

public class ControllerW {

@FXML
private Label statusLbl, timeLbl, textLbl;
@FXML
private Button exitBtn, linkBtn;

private ServerSocket serverSckt;
private Socket clientSckt;
DataInputStream dis;
String text;

@FXML
private void exit() {
    System.exit(0);
}

@FXML
private void linkAndroid() {
    try {
        serverSckt = new ServerSocket(5678);
        statusLbl.setText("Server started");
        clientSckt = serverSckt.accept();
        statusLbl.setText("client connected successfully");
        dis = new DataInputStream(clientSckt.getInputStream());
        text = dis.toString();
        textLbl.setText(text);
    } catch (Exception e) {
        statusLbl.setText("No connection on port 5678");
        e.printStackTrace();
    }
}

}

Я новичок в программировании сокетов, может кто-нибудь помочь мне, если что-то не так с моим кодом

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Сначала вы запускаете сокет с потоком GUI / JFX.так что accept() заблокирует его (пользовательский интерфейс не будет отвечать, круг знакомых вам известен).

Вам необходимо запустить IO / сокет с другим потоком.но будьте осторожны, вам нужно изменить содержимое пользовательского интерфейса с потоком пользовательского интерфейса.(например, textLbl.setText(text); может завершиться ошибкой, если вызывается из другого потока напрямую)

Также эта строка text = dis.toString(); является бессмысленной, вы должны получить строку, отправленную от клиента?Поэтому используйте (рекомендуется) readLine() метод из BufferedReader вместо DataInputStream.(readUTF может работать и с DataInputStream).

0 голосов
/ 30 мая 2018

Ваше приложение перестает отвечать, потому что оно не является многопоточным.Без многопоточности ваше приложение будет «остановлено» в тот момент, когда вы нажмете кнопку «ссылка», потому что вызов ServerSocket#accept.

Причиной этого является блокировка природа метода accept.Пока другой сокет не соединится, ServerSocket ожидает и удерживает свой текущий поток "приостановленным".Думайте об этом как о внутреннем цикле while, подобном этому:

while(!isConnected())
{
    // check if there is a new request
}

Представьте себе, что ни один клиент никогда не подключится.Как эта петля когда-нибудь остановится?Никогда.

Возможный обходной путь - это поточная обработка всей части пользовательского интерфейса или части «модели данных».

Мой предпочтительный способ - создать собственный класс, который обрабатывает только метод ServerSocket#accept иделегирует входящие соединения другому потоку, который заботится обо всем остальном.Я делаю это для того, чтобы мой сервер был доступен в любое время, что может быть не лучшим решением для вашей проблемы.

Вот как обычно выглядит мой вспомогательный класс:

ClientAccepter.java:

public class ClientAccepter
    implements Runnable
{
  // the ServerSocket
  private final ServerSocket server;
  // ExecutorServices ease the pain of threading your application quite a lot
  private final ExecutorService es = Executors.newCachedThreadPool();

  private boolean isAlive = true;

  public ClientAccepter( ServerSocket server )
  {
    this.server = server;
  }

  @Override
  public void run()
  {
    //This is where you specify your desired behaviour.
    //Example:
    while ( isAlive )
    {
      try
      {
        es.execute( new ClientHandler( server.accept() ) );
      }
      catch ( IOException e )
      {
        e.printStackTrace();
      }
    }
  }
}

Вызов такого класса может выглядеть следующим образом:

Server.java:

public class Server
{
  //ExecutorServices are the best and easy to use.
  private static ExecutorService serverThreader = Executors.newSingleThreadExecutor();

  public static void main( String[] args )
  {
    try
    {
      serverThreader.execute( new ClientAccepter( new ServerSocket( 8080 ) ) );
    }
    catch ( IOException e )
    {
      e.printStackTrace();
     //further exception handling.
    }
  }
}

Toчестно говоря, это может быть не лучшим подходом, но это мой предпочтительный способ обработки операций блокировки.Вам следует подумать о работе с orcale параллельным учебником и определенно взглянуть на ExecutorServices, потому что они являются невероятной платформой для удобной обработки потоковых пулов.


Также специально для JavaFX существует руководство по параллелизму .

...