Связь с сервером и клиентом не работает на выходных потоках

Моя программа в основном:

  1. Клиент отправляет строку на сервер,

  2. На основе этой строки сервер создает список ArrayList,

  3. ArrayList отправляется обратно клиенту.

Что здесь не так:

После того, как Клиент отправляет строку, Сервер получает ее и больше ничего не делает. В это время Клиент продолжает работать и получает NullPointer.

На стороне клиента:

    public static ArrayList<String> sendStringToServer(String report) {

    Socket socket;

    ArrayList<String> fieldsList = new ArrayList<String>();

    try {

        socket = new Socket("localhost", 2345);

        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os, true);

        ps.println(report);
        ps.flush();

        //Here the debugger should stop and wait for server to create a List

        //at this point there is no answer, code breaks
        ObjectInputStream objectInput = new ObjectInputStream(socket.getInputStream());

        Object object = objectInput.readObject();
        fieldsList = (ArrayList<String>) object;

        socket.close();

        return fieldsList;

    } catch (IOException e1) {

        e1.printStackTrace();
    } catch (Exception e) {

        e.printStackTrace();
    }
    return null;
}

}

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

public class Server {

private ServerSocket serverSocket;
private Socket clientSocket;
private String telegram;
private StringBuilder telegramSB;

public static void main(String[] args) throws IOException, JRException {

    new Server();
}
public Server() {

    try {
        serverSocket = new ServerSocket(2345);

        while (true) {

            clientSocket = serverSocket.accept();
            InputStream is = clientSocket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            try {

                //debugger goes to here and then stops
                telegram = br.readLine();

                int counter = 0;

                boolean startSeq = false;

                for (char ch : telegram.toCharArray()) {

                    if (counter == 0 && ch == '/') {

                        startSeq = true;
                    }

                    if (startSeq == true) {

                        telegramSB = new StringBuilder();
                        telegramSB.append(ch);
                    }

                    if (ch == '\n') {

                        if (telegram.length() < 255) {

                            sendListWithFields();

                        } else {

                            new Launcher(telegram).run();
                        }
                    }
                    counter++;
                }
            } catch (JRException e) {

                e.printStackTrace();

            } catch (IOException e) {

                e.printStackTrace();

            }
        }
    } catch (IOException e) {

        System.out.println(e);
    }
}

person PRO_gramista    schedule 13.07.2015    source источник
comment
Вы отправляете символ конца строки (EOF)?   -  person Eduardo Yáñez Parareda    schedule 13.07.2015
comment
@eyp да, но моя программа так и не доходит. Он читает bufferedReader и затем останавливается.   -  person PRO_gramista    schedule 13.07.2015


Ответы (1)


Я предполагаю, что BufferedReader ожидает заполнения своего буфера, а вы не отправили достаточно данных, чтобы он сделал это и вернулся, поэтому он ждет, пока не пройдет больше данных, чего никогда не происходит (потому что ваши клиенты перестают писать и начинают читать). Вы можете временно проверить эту теорию, загрузив дополнительные данные в OutputStream на клиенте и сбросив их.

Если это так, то вы, вероятно, не захотите использовать BufferedReader, но у вас есть другие проблемы, которые также означают, что вы, вероятно, в любом случае не хотите использовать PrintStream и BufferedReader для связи и сериализации. Например, кодировка символов по умолчанию на двух разных машинах и JVM может быть разной. Когда вы создаете свои PrintStream и InputStreamReader, вы не указываете кодировку символов, поэтому они могут оказаться несоответствующими, и строка, которую вы пишете (включая символ новой строки), может быть совершенно иначе понята удаленной стороной, это также может быть причина его блокировки (клиентская сторона кодирует символ новой строки одним способом, но сервер ожидает, что он будет закодирован совершенно другим способом), хотя я думаю, что это менее вероятно.

Если у вас нет есть для использования PrintStream, я бы предложил вместо этого использовать DataOutputStream / DataInputStream:

//Client
BufferedOutputStream bufout = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dout = new DataOutputStream(bufout);
dout.writeUTF(report);
dout.flush();

//Server
BufferedInputStream bufin = new BufferedInputStream(socket.getInputStream());
DataInputStream din = new DataInputStream(bufin);
String report = din.readUTF();

Вы по-прежнему получаете буферизацию из BufferedIn / OutputStreams, поэтому она будет производительной, но DataIn / OutputStreams будут управлять завершением объектов переменной длины за вас - они отправят префикс длины строки, чтобы сообщить другой стороне, сколько именно байтов нужно прочитать, поэтому вам не нужно использовать специальный символ для завершения написанной вами строки, и это также означает, что не имеет значения, каково содержимое вашей String. В приведенном выше примере, даже если он работал, если в вашей строке был символ новой строки, сервер будет читать до этого первого символа новой строки, а не до конца отправленной вами строки, и это приведет к их рассинхронизации для следующей отправки / получить по этому потоку.

Использование write / readUTF также указывает кодировку (UTF-8), поэтому и здесь нет несоответствия.

person AntonyM    schedule 17.07.2015