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

11,383

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.

Share:
11,383
Josh
Author by

Josh

Student at NTNU in Trondheim, Norway.

Updated on June 22, 2022

Comments

  • Josh
    Josh almost 2 years

    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?

  • Josh
    Josh over 11 years
    What I was looking for is whether or not we are guaranteed that the method will only block until data has arrived or EOS is signalled, and not block waiting for the entire supplied buffer to be filled before returning. Note that when you look into the source code for the base class InputStream.java this is not the case. The read(byte[]) method there will do read()-calls until the buffer is filled. I guess you gave the answer I was looking for, thank you :) Do you perhaps have a source for this btw?
  • nos
    nos over 11 years
    @runaros That said, socket.getInputStream() actually gives a subclass of InputStream , the internal java.net.SocketInputStream class from what I can see. This class overrides the read() methods of java.io.InputStream, and can behave differently than the code you pulled out of java.io.InputStream
  • user207421
    user207421 over 9 years
    @runaros My source is the specification of InputStream.read() in the Javadoc. It says exactly what I have said here: 'there is an attempt to read at least one byte'.
  • user207421
    user207421 about 6 years
    @runaros You should also note the comment in the Javadoc of InputStream.read(byte[], int, int) that says 'subclasses are encouraged to provide a more efficient implementation of this method', and every subclass I can think of does so.