Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scanner.nextLine() blocks when using InputStream from Socket

When I receive data using Socket.getInputStream() directly (without some kind of interface like Scanner), it doesn't block. But, when I try to use a Scanner (similar to how we receive Strings from System.in), it does. I was wondering the reason for this, and how the InputStream that a connected Socket supplies to you is different from the InputStream in in System.

The Client used for testing (used for both servers)

The code that hangs:

public class Server {

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(15180);
            Socket socket = ss.accept();

            Scanner scanner = new Scanner(socket.getInputStream());
            //read data from client
            while(true) {
                String data = scanner.nextLine();
                System.out.println("Received data!");
            }

        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

The code that doesn't block:

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(15180);
            Socket socket = ss.accept();

            //read data from client
            while(true) {
                int data = socket.getInputStream().read();
                System.out.println("Received data!");
            }

        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}
like image 606
Vince Avatar asked Jul 19 '14 22:07

Vince


People also ask

Is Scanner nextLine blocking?

However, if you construct a Scanner using an InputStream that may require waiting for data to arrive (e.g., reading text from a remote client, waiting for a page to load so you can read its source, etc.) then Scanner#nextLine() will block because it needs to wait for enough information to build the next line to arrive.

Why does Scanner skip nextLine ();?

That's because the Scanner. nextInt method does not read the newline character in your input created by hitting "Enter," and so the call to Scanner. nextLine returns after reading that newline. You will encounter the similar behaviour when you use Scanner.

What is the use of nextLine () method in Scanner class?

The nextLine() method of the java. util. Scanner class scans from the current position until it finds a line separator delimiter. The method returns the String from the current position to the end of the line.

What does nextLine () do?

nextLine() method advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.


1 Answers

(I think you've already figured this out but ...)

The readLine() method returns the rest of the current line. That is, all unconsumed characters up to the next "end of line" sequence, or the "end of stream", which ever comes first. It will block, waiting until the current line (according to the above) is available.

So if your socket readLine() call blocks, it is waiting for the remote to either send an end-of-line marker (e.g. '\n'), or close its socket output stream (which will result in an "end-of-stream" at this end).

Q: Why does it "work" when you read from the console?

A: The console adds an "end-of-line" sequence to the stream whenever you hit ENTER. (Precisely what sequence is added is OS dependent, but the Scanner class will cope with all common varieties, and some unusual ones too.)


The lesson here is that you should only use Scanner.readLine() if the input stream is line oriented; i.e. if whatever wrote / generated the stream is including "end-of-line" markers.

like image 120
Stephen C Avatar answered Sep 29 '22 00:09

Stephen C