Search code examples
javaserverbufferedreader

Java - BufferedReader Stalls without an Escape Character


I am building a server in Java, and the input feed is giving me trouble - its current setup cannot read more than one line, and it cannot read anything without "\n" at the end. Here is the current input loop:

BufferedReader input = new BufferedReader(new InputStreamReader(serverConnection.getInputStream()));

    if(input.ready()){

        StringBuilder text = new StringBuilder();
        String line;


        while((line = input.readLine()) != null){

            text.append(line);
            System.out.println(line);

        }

        sentData = text.toString();
        return true;
    }

My current loop using a BufferedReader cannot read more than one line of incoming data, and if there is no newline character, a timeout exception is thrown (I programmed it to do that), and the data is not read at all. It is, of course, unacceptable to have a listener that can only see one line of data, and stalls when the sent data is not formatted properly.

So I am looking for a method that allows the program to read any number of lines, and for the program to stop reading when it has reached the end of the data stream (even without a new line).

Any help is appreciated.


Solution

  • You can read from the InputStream directly into the StringBuilder. readLine() of BufferedReader will wait for \r or \n character. This looks like stalling.

    int ch;
    StringBuilder text = new StringBuilder();
    while((ch = serverConnection.getInputStream().read())!= -1) { // -1 will be read at EOS
        text.append((char)ch);
    }
    sentData = text.toString();
    return true;
    

    Update

    The following piece of code is to demonstrate the difference between usage of BufferedReader and InputStream to read bytes and what is available to the user during read operation. BufferedReader will always give you lines which are either terminated by line breaks or by EOS. Whereas InputStream will make the available bytes to the user.

    In scenarios where it is NOT necessary to close the streams, and the bytes transferred has it's own way to mark start and end of packets/messages, you will be using InputStream to read bytes. If you try using BufferedReader for these applications, the last line of the message will be made available once the server receives the next packet/message, unless you send each line with a line-break.

        public static void main(String[] args) throws Exception {
            new Thread(new BufferedReaderServer()).start();
            new Thread(new InputStreamServer()).start();
            final String requestString = "Line#1\nLine#2";
    
            System.out.println("\nSending to BufferedReaderServer");
            Socket clientSocket1 = new Socket(InetAddress.getLocalHost()
                    .getHostAddress(), 8003);
            OutputStream outputStream1 = clientSocket1.getOutputStream();
            outputStream1.write(requestString.getBytes());
            Thread.sleep(6000);
            outputStream1.close();
            clientSocket1.close();
    
            Thread.sleep(1000);
            System.out.println("\nSending to InputStreamServer");
    
            Socket clientSocket2 = new Socket(InetAddress.getLocalHost()
                    .getHostAddress(), 8004);
            OutputStream outputStream2 = clientSocket2.getOutputStream();
            outputStream2.write(requestString.getBytes());
            Thread.sleep(6000);
            outputStream2.close();
            clientSocket2.close();
        }
    
        static class BufferedReaderServer implements Runnable {
    
            public void run() {
                ServerSocket serverSocket = null;
                try {
                    serverSocket = new ServerSocket(8003);
                    Socket socket = serverSocket.accept();
                    BufferedReader bufferedReader = new BufferedReader(
                            new InputStreamReader(socket.getInputStream()));
                    String s = null;
                    System.out.println("BufferedReaderServer read START");
                    while ((s = bufferedReader.readLine()) != null) {
                        System.out.println(s);
                    }
                    System.out.println("BufferedReaderServer read END");
                    socket.getInputStream().close();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        serverSocket.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        static class InputStreamServer implements Runnable {
    
            public void run() {
                ServerSocket serverSocket = null;
                try {
                    serverSocket = new ServerSocket(8004);
                    Socket socket = serverSocket.accept();
                    System.out.println("InputStreamServer read START");
                    int ch;
                    while ((ch = socket.getInputStream().read()) != -1) {
                        System.out.print((char) ch);
                    }
                    System.out.println("\nInputStreamServer read END");
                    socket.getInputStream().close();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        serverSocket.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    The issue what is being faced here could be due to non-closing of client socket. Depends on the user's application