Почему мой соединитель не получает сообщение хоста?

#java #sockets

#java #сокеты

Вопрос:

Краткие сведения

Я создаю простую одноранговую шахматную игру на Java. Хост успешно подключается, но соединитель не получает свое сообщение. Я использую PrintWriter и BufferedReader для отправки и получения сообщений. Я подозреваю, что PrintWriter неправильно себя ведет, но я не уверен.

Предварительное исследование

Я искал «Клиент, не получающий сообщение сервера», но проблема, с которой все сталкивались, заключалась в том, что они не использовали println со своим PrintWriter . Я использую println , поэтому ни один из них не применялся ко мне. Я также переместил поля ввода и вывода из метода в класс, что и было сказано в одном ответе, но это не решило проблему.

Некоторый код

Прослушивающий код

 try (ServerSocket serverSocket = new ServerSocket(this.port)) {
    // We need to connect with another computer
    if (this.other == null || this.other.isClosed()) {
        System.out.println("Looking for connection on port "   serverSocket.getLocalPort());
        this.in = null;
        this.out = null;
        // Listen for connectors
        this.other = serverSocket.accept();
        // Someone tried to connect, handle connection
        System.out.println("Player connected");
        this.in = new BufferedReader(new InputStreamReader(this.other.getInputStream()));
        this.out = new PrintWriter(this.other.getOutputStream(), true);
        // Autoflush is enabled!                                 ^^^^
        // This does not get to the client
        this.sendMessage("connectHost");
    }
    // We are currently connected to another computer, no need to look for more
    else {
        String input = this.in.readLine();
        System.out.println("Received '"   input   "'");
        
        if (input != null) {
            // Handle input
        }
    }
} catch (IOException ioe) {
    ioe.printStackTrace();
}
  

Отправка кода

 if (this.out != null) {
    // See, it is println, so I don't need to call out.flush()...
    this.out.println(message);
    System.out.println("Sent '"   message   "'");
}
  

Код команды подключения

 try {
    // The host picks up on this
    this.other = new Socket(ip, port);
    this.in = new BufferedReader(new InputStreamReader(this.other.getInputStream()));
    this.out = new PrintWriter(this.other.getOutputStream(), true);
    // Works
    this.sendMessage("test");
} catch (IOException ioe) {
    ioe.printStackTrace();
}
  

Проблема

Оно должно быть распечатано Received 'connectHost' на соединителе, но этого не происходит. Вместо этого он блокирует, от in.readLine() вызова без in получения данных. Если я вставлю in.ready() проверку, она всегда будет возвращаться false .

Консоль соединителя

 Looking for connection on port 57479
connect localhost 57478 // Command to connect to host
Sent 'test' // Successfully goes to the host
// Now it blocks. This is intended, but it should be saying "Received 'connectHost'" beforehand.
  

Консоль хоста

 Looking for connection on port 57478
Player connected
Sent 'connectHost'
Received 'test' // Host gets it
// This also blocks, waiting for more messages, but that is intended.
  

Обновить:
Я просто попытался отправить сообщение непосредственно после подключения (см. Обновленный код), и хост его получает. Соединитель по-прежнему не получает сообщение от хоста.

Комментарии:

1. Где находится код, который печатает то, что вы обозначили как «консоль соединителя»?

2. Если вы отправляете (и получаете) как с сервера, так и с клиента, вам понадобятся отдельные потоки для каждого прослушивающего сокета

3. «Код подключения» не устанавливается this.in или this.out, это намеренно?

4. @Scary Wombat Запущено два экземпляра одного и того же кода.

5. @immibis Увидев ваш комментарий, я попробовал, но без разницы.

Ответ №1:

Это было очевидно…

serverSocket.accept() Была блокировка, не позволяющая соединителю считывать входные данные. Итак, in.readLine() проблема не в этом. Я сделал это так, чтобы пользователь должен был указать программе прослушивать соединения. Теперь это работает.

Новый код

Прослушивающий код

 try (ServerSocket serverSocket = new ServerSocket(this.port)) {
    if (this.listening amp;amp; (this.other == null || this.other.isClosed())) {
        System.out.println("Looking for connection on port "   serverSocket.getLocalPort());
        this.in = null;
        this.out = null;
        this.other = serverSocket.accept();
        this.in = new BufferedReader(new InputStreamReader(this.other.getInputStream()));
        this.out = new PrintWriter(this.other.getOutputStream(), true);
    } else if (this.in != null) {System.out.println("Looking for input");
        String input = this.in.readLine();
        System.out.println("Received '"   input   "'");

        if (input != null) {
            // Process input
        }
    }
} catch (IOException ioe) {
    ioe.printStackTrace();
}
  

Код отправки не изменился.

Код подключения

 if (input.contains("connect")) {
    String[] args = input.replaceAll("connect ", "").split(" ");
    String ip = args[0];
    int port = Integer.parseInt(args[1]);

    try {
        this.other = new Socket(ip, port);
        this.in = new BufferedReader(new InputStreamReader(this.other.getInputStream()));
        this.out = new PrintWriter(this.other.getOutputStream(), true);
        this.sendMessage("connect");
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
} else if (input.contains("listen")) {
    this.listening = true;
}