Проблема с потоками ввода вывода в Socket

226
26 июня 2018, 05:20
Проблема с отправкой и получением данных.

Тренируюсь работать с потоками ввода и вывода в Socket'ах. То есть со стороны клиента по нажатию кнопки у меня создаётся поток, который создаёт строку и выводит её в полученный из Socket'а OutputStream. После этого в цикле while() я жду ответа от сервера.

Вот этот код:

new Thread(() -> {
                try {
                    socket = new Socket();
                    socket.connect(new InetSocketAddress("127.0.0.1", DEFAULT_PORT));
                    InputStream is = socket.getInputStream();
                    OutputStream os = socket.getOutputStream();
                    String str = "/reg/ %" + fieldName.getText() + "%" + fieldPassword.getText()+"%";
                    BufferedWriter writer = new BufferedWriter(new PrintWriter(os, true));
                    writer.write(str);
                    writer.flush();
                    int suc = 0;
                    while((suc = is.read()) != -1) {
                            if (suc == 1) {
                                area.setText("You was successfully registered!");
                            }else if(suc==0){
                                area.setText("Your login is already used!");
                            } else {
                                area.setText("Error connected");
                            }
                    }

                }catch (SocketException exception)
                { exception.printStackTrace(); }
                catch (IOException exception)
                { exception.printStackTrace(); }
            }).start();

    });

Со стороны сервера я жду соединения, для каждого соединения создаю новый поток, считываю первые 5 байтов - информация о последующей строке. В данном случае он получает строку "/reg/" и спрашивает, если метод register = true,то пишет 1 - удача, иначе 0 - неудача.

Вот код:

private void manage(Socket uSocket){
    manageThread = new Thread(() -> {
    long id = getID();
            try {
                byte[] tokenBytes = new byte[5];
                InputStream is = uSocket.getInputStream();
                OutputStream os = uSocket.getOutputStream();
                is.read(tokenBytes);
                String token = new String(tokenBytes);
                switch (token){
                    case "/mes/":
                        break;
                    case "/reg/":
                        System.out.println("В блоке рег");
                        if(register(new BufferedReader(new InputStreamReader(is)), id)){
                            os.write(1);
                        }else{
                            os.write(0);
                        }
                        break;
                    case "/log/":
                        break;
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
    clientSockets.put(id, userSocket);
    }, "manageThread");
    manageThread.start();
}

Метод register здесь в третьей строке сервер просто зависает, скорей всего из-за метода is.readLine() :

private boolean register(BufferedReader is, long id) throws IOException{
    System.out.println("В регистере");
    String[] data = is.readLine().split("%");//В этом месте сервер зависает
    System.out.println("В регистере прочитал");
    try(ManageDatabase database = new ManageDatabase()){
        if(!database.checkLogin(data[1])){
            System.out.println("Проверил");
            return false;
        }
        clients.put(id, new Person(data[1], data[2], id));
        database.addUser(data[1], data[2], id);
    }catch (IOException e){}
    is.close();
    return true;
}

Мне надо, чтобы он считывал эту строку и далее выдавал либо true либо false, дальше OutputStream бы записывал это и Client принимал успех или неудача, что изменяло бы TextArea, но видимо эти потоки ввода-вывода ждут друг друга.

Подскажите, что делаю неправильно, буду рад любой помощи.

Answer 1

Согласно документации метод readLine читает поток до тех пор, пока ему не встретится символ \r или \n (или оба: \r\n). Вы же эти символы от клиента не передаёте, поэтому метод на сервере всё ждёт и ждёт.

Вариантов тут есть как минимум два:

  • Передавать \n. Изменения в этом случае в коде будут минимальны: можно прямо вместо ненужного + "%" в конце строки кода написать + "\n"
  • Передавать длину строки запроса непосредственно перед этой строкой, а на сервере считывать длину и соответствующее количество символов следом. В этом случае передавать \n не придётся (но и метод в этом случае нужно использовать не readLine)
READ ALSO
Java СlassNotFoundException oracle.jdbc.OracleDriver

Java СlassNotFoundException oracle.jdbc.OracleDriver

После создания артефакта (jar файл) в IntellIJ, при подключении к DB Oracle на RDS Amazon, выдает ошибку: СlassNotFoundException oracle

220
При обновлении версии градл до 3.1.2 получаю ошибку

При обновлении версии градл до 3.1.2 получаю ошибку

Сейчас использую в проекте градл версии 23

230
Некорректная работа(код) onTimeSet() c несколькими TimePicker

Некорректная работа(код) onTimeSet() c несколькими TimePicker

Не до конца понятно как корректно написать функцию onTimeSet() для работы с несколькими TimePicker из фрагментовГуглил, но ничего, чтобы помогло не нашел

223
Хранение данных Java

Хранение данных Java

Имеется программа на Java, представляющая из себя небольшую таблицу приблизительно в 10 столбцов

195