Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Socket.getInputStream().read(byte[]) guaranteed to not block after at least some data is read?

The JavaDoc for the class InputStream says the following:

Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.

This corresponds to my experience as well. See for instance the example code below:

Client:
Socket socket = new Socket("localhost", PORT);
OutputStream out = socket.getOutputStream();
byte[] b = { 0, 0 };
Thread.sleep(5000);
out.write(b);
Thread.sleep(5000);
out.write(b);

Server:
ServerSocket server = new ServerSocket(PORT);
Socket socket = server.accept();
InputStream in = socket.getInputStream();
byte[] buffer = new byte[4];
System.out.println(in.read(buffer));
System.out.println(in.read(buffer));

Output:
2   // Two bytes read five seconds after Client is started.
2   // Two bytes read ten seconds after Client is started.

The first call to read(buffer) blocks until input data is available. However the method returns after two bytes are read, even though there is still room in the byte buffer, which corresponds with the JavaDoc stating that 'An attempt is made to read as many as len bytes, but a smaller number may be read'. However, is it guaranteed that the method will not block once at least one byte of data is read when the input stream comes from a socket?

The reason I ask is that I saw the following code in the small Java web server NanoHTTPD, and I wondered if a HTTP Request smaller than 8k bytes (which most requests are) potientially could make the thread block indefinately unless there is a guarantee that it won't block once some data is read.

InputStream is = mySocket.getInputStream();
// Read the first 8192 bytes. The full header should fit in here.
byte[] buf = new byte[8192];
int rlen = is.read(buf, 0, bufsize);

Edit:

Let me try to illustrate once more with a relatively similar code example. EJP says that the method blocks until either EOS is signalled or at least one byte of data has arrived, in which case it reads however many bytes of data have arrived, without blocking again, and returns that number, which corresponds to the JavaDoc for method read(byte[], int, int) in the class InputStream. However, if one actually looks at the source code it is clear that the method indeed blocks until the buffer is full. I've tested it by using the same Client as above and copying the InputStream-code to a static method in my server example.

public static void main(String[] args) throws Exception {
    ServerSocket server = new ServerSocket(PORT);
    Socket socket = server.accept();
    InputStream in = socket.getInputStream();
    byte[] buffer = new byte[4];
    System.out.println(read(in, buffer, 0, buffer.length));
}

public static int read(InputStream in, byte b[], int off, int len) throws IOException {
    if (b == null) {
        throw new NullPointerException();
    }
    else if (off < 0 || len < 0 || len > b.length - off) {
        throw new IndexOutOfBoundsException();
    }
    else if (len == 0) {
        return 0;
    }

    int c = in.read();
    if (c == -1) {
        return -1;
    }
    b[off] = (byte)c;

    int i = 1;
    try {
        for (; i < len; i++) {
            c = in.read();
            if (c == -1) {
                break;
            }
            b[off + i] = (byte)c;
        }
    }
    catch (IOException ee) {
    }
    return i;
}

This code will have as its output:

4   // Four bytes read ten seconds after Client is started.

Now clearly there is data available after 5 seconds, however the method still blocks trying to fill the entire buffer. This doesn't seem to be the case with the input stream that Socket.getInputStream() returns, but is it guaranteed that it will never block once data is available, like the JavaDoc says but not like the source code shows?

like image 468
runaros Avatar asked Nov 06 '12 08:11

runaros


People also ask

What does getInputStream return?

getInputStream. This method returns an InputStream representing the data and throws the appropriate exception if it can not do so.

How does InputStream read work?

read() method reads the next byte of the data from the the input stream and returns int in the range of 0 to 255. If no byte is available because the end of the stream has been reached, the returned value is -1.

Which is the byte based input stream to read files In Java?

FileInputStream is meant for reading streams of raw bytes such as image data. For reading streams of characters, consider using FileReader. 1. FileInputStream(File file): Creates an input file stream to read from the specified File object.

How to read data from InputStream In Java?

read(byte[] b) method of DataInputStream class in Java is used to read bytes from the input stream and store them into the buffer byte array. This read() method returns the number of bytes actually read as an integer type. This method returns -1 if the input stream is ended and no more data is available to read.


1 Answers

However, is it guaranteed that the method will not block once at least one byte of data is read when the input stream comes from a socket?

I don't think this question means anything. The method blocks until either EOS is signalled or at least one byte of data has arrived, in which case it reads however many bytes of data have arrived, without blocking again, and returns that number.

I saw the following code in the small Java web server NanoHTTPD

The code is wrong. It makes the invalid assumption that the entire header will be delivered in the first read. I would expect to see a loop here, that loops until a blank line is detected.

I wondered if a HTTP Request smaller than 8k bytes (which most requests are) potientially could make the thread block indefinitely unless there is a guarantee that it won't block once some data is read.

Again I don't think this means anything. The method will block until at least one byte has arrived, or EOS. Period.

like image 112
user207421 Avatar answered Oct 15 '22 03:10

user207421