繁体   English   中英

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

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

InputStream类的JavaDoc表示以下内容:

从输入流中读取最多len个字节的数据到一个字节数组中。 尝试读取多达len个字节,但可能读取的字节数较小。 实际读取的字节数以整数形式返回。 该方法将阻塞,直到输入数据可用,检测到文件结尾或引发异常为止。

这也符合我的经验。 例如,请参见下面的示例代码:

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.

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

我问的原因是,我在小型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);

编辑

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

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;
}

此代码将作为其输出:

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

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

但是,是否可以保证当输入流来自套接字时,一旦读取至少一个字节的数据,该方法就不会阻塞?

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

我在小型Java Web服务器NanoHTTPD中看到以下代码

代码错误。 它做出无效的假设,即在第一次读取时将传递整个标头。 我希望在这里看到一个循环,一直循环到检测到空白行。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM