Как остановить Java Socket клиент продолжает отправлять «нулевые» данные? - PullRequest
0 голосов
/ 02 февраля 2019

Я создал 2 Java-программы с сокетами в нем.Я хочу, чтобы клиент отправлял непрерывные данные на сервер.Но после того, как сообщение отправлено на сервер, клиент продолжает отправлять на сервер значение 'null' (это происходит, когда я закрываю сокет в клиентской программе).Вот мои коды:

import ...
public class MainClient {
    private Socket serverSock;
    private PrintStream clientOutput;

    public static void main(String[] args) {
        MainClient client = new MainClient();
        client.runClient();
    }
    public void runClient() {
        try {
            serverSock = new Socket("127.0.0.1",8282);
            clientOutput = new PrintStream(serverSock.getOutputStream());
            clientOutput.println("Hello, I'm Connected.");

            for (int i=0;i<5;i++) {
                clientOutput.println(i + "");
                clientOutput.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
//          try {
//              serverSock.close(); It will keeps sending 'null' data to the server if I use this line.
//          } catch (IOException e) {
//              e.printStackTrace();
//          }
        }
    }
}

На стороне сервера:

public class MainServer {

    private ServerSocket serverSocket;
    private int listenPort = 8282;
    private InputStream inps;
    private Socket clientSocket;
    private BufferedReader clientInput;

    private MainServer() {
        String clientMsg = "";
        try {
            serverSocket = new ServerSocket(listenPort);
            System.out.println("Server is Listening on " + listenPort);
            clientSocket = serverSocket.accept();
            clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            while(clientSocket.isConnected()) {
                clientMsg = clientInput.readLine();
                System.out.println("Client : " + clientMsg);                
            }
        }catch(IOException ex) {
            ex.printStackTrace();
        }finally {
            try {
                clientSocket.close();
            } catch (IOException e) {}
        }
    }
    public static void main(String[] args) {
        new MainServer();
    }
}

Я пытался закрыть OutputStream на стороне клиента с помощью clientOutput.close();, но после этого он отправляет нулевые значения на серверотправляет цикл 0-4.Чтобы это остановить и избежать отправки клиентом нулевых данных, я не должен вставлять serverSock.close(); на клиенте, но он возвращает SocketException.Я хотел, чтобы клиент отправил сообщение «Закрыто» после его завершения.

Сводка, выходные данные на сервере:

Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Client: null
Client: null
//And so on..

Я думаю, что в клиентской программе чего-то не хватает, яУгадай?Спасибо за помощь:)

Ответы [ 3 ]

0 голосов
/ 02 февраля 2019

Ваш MainClient () не имеет проблем.

Функция clientSocket.isConnected () в MainServer () всегда проверяет состояние клиента и приводит к бесконечному циклу, поэтому после сообщения «client: 4»clientInput.readLine () должен возвращать 'null'.

Таким образом, вместо того, чтобы проверить, подключен ли клиентский сокет или нет, вы можете проверить, что клиентский сокет закрыт или не использует функцию clientSocket.isClosed () '.

замените цикл while в MainServer () следующим кодом:

       while(!clientSocket.isClosed()) {

                clientMsg = clientInput.readLine();
                System.out.println("Client : " + clientMsg);

                if(clientMsg.equals("Closed")){
                     clientSocket.close();
                //  serverSocket.close();
                }
            }

это поможет вам закрыть клиентский сокет во время получения сообщения «Закрыто» с сервера, и это позволит избежатьбесконечное выполнение цикла while и печать нулевых операторов.Код «serverSocket.close ()» поможет вам закрыть сокет сервера, и вы можете использовать его в «MainServer ()», если вам нужно остановить прослушивание порта.

0 голосов
/ 02 февраля 2019

Как отмечено в комментарии, клиент не отправляет значение null.

Метод isConnected() не выполняет то, что вы думаете, а именно не сообщаетвы, если сокет в настоящее время «подключен» к своему партнеру, по крайней мере, так, как вы думаете.isConnected() становится истинным, как только сокет переходит в подключенное состояние, и остается верным после этого даже после выключения сокета.См. в этом обсуждении и др., Посвященном стековому потоку.

Правильный способ определить, отключил ли одноранговый узел соединение, - это попытаться прочитать данные из сокета, а затем проверить результат на наличие признаков закрытия.Пожалуйста, прочитайте Javadocs для метода, который вы используете, они скажут вам, что означают различные возвращаемые значения.Для метода BufferedReader.readLine() он говорит:

Возвращает:
Строка, содержащая содержимое строки, не включая строки.символы завершения или ноль, если достигнут конец потока
Броски:
IOException - Если возникает ошибка ввода-вывода

Таким образом, вам нужнопроверьте нулевое возвращаемое значение, чтобы обнаружить нормальное закрытие сокета, и если вы получаете IOException, которое указывает на какую-то сетевую аномалию.

0 голосов
/ 02 февраля 2019

обычно код должен быть чем-то похожим

private MainServer() {
  String clientMsg = "";
  try {
    serverSocket = new ServerSocket(listenPort);
    System.out.println("Server is Listening on " + listenPort);
    clientSocket = serverSocket.accept();
    clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    while ((clientMsg = clientInput.readLine()) != null) {
      if(isTerminationString(clientMsg)) { 
        break;
      }
      System.out.println("Client : " + clientMsg);
    }
  } catch (IOException ex) {
    ex.printStackTrace();
  } finally {
    try {
      clientSocket.close();
    } catch (IOException e) {
    }
  }
}

boolean isTerminationString(String msg) {
  return msg.equals("DONE!");
}

, где в isTerminationString вы проверяете, является ли сообщение msg завершением, протокол связи должен быть разделен между клиентом и сервером.я привел пример отправки сообщения DONE , но оно может быть более сложным, чем это.поскольку закрытие метода close в сокете не гарантирует, что сокет в другой части также будет закрыт, использование метода isClosed может оказаться неэффективным и приведет к той же проблеме, что и у вас.

...