java Socket.getInputStream().read(byte[]) 是否保证在至少读取一些数据后不会阻塞?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13247410/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 12:01:12  来源:igfitidea点击:

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

javaioinputstream

提问by runaros

The JavaDoc for the class InputStream says the following:

InputStream 类的 JavaDoc 说明如下:

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.

从输入流中读取最多 len 个字节的数据到一个字节数组中。尝试读取多达 len 个字节,但可能会读取较小的数字。实际读取的字节数作为整数返回。此方法会阻塞,直到输入数据可用、检测到文件结尾或抛出异常。

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?

第一次调用 read(buffer) 会阻塞,直到输入数据可用。然而,该方法在读取两个字节后返回,即使字节缓冲区中仍有空间,这与 JavaDoc 声明“尝试读取多达 len 个字节,但可能读取数字较小”相对应。但是,当输入流来自套接字时,是否保证一旦至少读取了一个字节的数据,该方法就不会阻塞?

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.

我问的原因是我在小型 Java Web 服务器NanoHTTPD 中看到了以下代码,我想知道小于 8k 字节(大多数请求是)的 HTTP 请求是否可能使线程无限阻塞,除非有保证一旦读取一些数据就不会阻塞。

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 JavaDocfor 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.

让我尝试用一​​个相对相似的代码示例再次说明。EJP 表示该方法会阻塞,直到 EOS收到信号或至少有一个字节的数据到达,在这种情况下,它会读取已到达的数据字节数,而不会再次阻塞,并返回该数字,这对应于方法的JavaDoc类 InputStream 中的 read(byte[], int, int)。但是,如果您实际查看源代码,很明显该方法确实会阻塞,直到缓冲区已满。我已经通过使用与上面相同的客户端并将 InputStream 代码复制到我的服务器示例中的静态方法来测试它。

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 guaranteedthat it will never block once data is available, like the JavaDoc says but not like the source code shows?

现在很明显有 5 秒后可用的数据,但是该方法仍然阻止尝试填充整个缓冲区。Socket.getInputStream() 返回的输入流似乎不是这种情况,但是它是否保证一旦数据可用就永远不会阻塞,就像 JavaDoc 所说但不像源代码显示的那样?

回答by user207421

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.

我认为这个问题没有任何意义。该方法会阻塞,直到 EOS 收到信号或至少有一个字节的数据到达,在这种情况下,它会读取已到达的数据字节数,而不会再次阻塞,并返回该数字。

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

我在小型Java Web服务器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.

我想知道小于 8k 字节(大多数请求都是)的 HTTP 请求是否可能使线程无限期地阻塞,除非保证一旦读取某些数据它就不会阻塞。

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

我再次认为这没有任何意义。该方法将阻塞,直到至少有一个字节或 EOS 到达。时期。