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

时间:2012-11-06 08:47:27

标签: java io inputstream

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

修改

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

此代码将作为其输出:

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

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

1 个答案:

答案 0 :(得分:5)

  

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

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

  

我在小型Java Web服务器NanoHTTPD

中看到了以下代码

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

  

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

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