首页 文章

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

提问于
浏览
8

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(缓冲区)阻塞,直到输入数据可用 . 但是,该方法在读取两个字节后返回,即使字节缓冲区中仍有空间,这与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);

Edit

让我尝试用相对类似的代码示例再次说明 . EJP说该方法阻塞,直到EOS被发信号或至少有一个字节的数据到达,在这种情况下,它读取了许多字节的数据已经到达,没有再次阻塞,并返回该数字,这对应于方法的JavaDoc在InputStream类中读取(byte [],int,int) . 但是,如果实际查看源代码,很明显该方法确实会阻塞,直到缓冲区已满 . 我已经使用与上面相同的客户端测试了它,并将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说的那样但不像源代码所示?

1 回答

  • 5

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

    我不认为这个问题意味着什么 . 该方法将阻塞,直到EOS被发信号通知或至少有一个字节的数据到达,在这种情况下,它会读取许多字节的数据,而不会再次阻塞,并返回该数字 .

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

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

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

    我再也不认为这意味着什么 . 该方法将阻塞,直到至少一个字节到达,或EOS . 期 .

相关问题