当前位置: 首页 > 知识库问答 >
问题:

是插座。getInputStream()。读取(字节[])保证在至少读取一些数据后不会阻塞?

壤驷阳波
2023-03-14

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.

第一次调用读取(缓冲)块,直到输入数据可用。然而,该方法在读取两个字节后返回,即使字节缓冲区中仍有空间,这与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类中方法读取的JavaDoc(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;
}

此代码将具有以下内容作为其输出:

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

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

共有1个答案

常永长
2023-03-14

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

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

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

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

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

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

 类似资料:
  • bufferedinputstream(BIS)比FileInputStream(FIS)快的原因请参见“为什么使用bufferedinputstream逐字节读取文件比使用FileInputStream快?”?是吗 使用BufferedInputStream,该方法委托给重载read()方法,该方法读取8192个字节,并在FIS读取单个字节时缓冲它们,直到需要它们 据我所知,磁盘是一个“块设备”

  • 据我所知,缓冲阅读器比非缓冲阅读器优化了很多,因为每次读取都将从内存中完成,不需要每次都从磁盘/网络进行I/O读/写。 所以我在这里阅读答案: 缓冲读取器和文件读取器之间的特定区别 我被第二个答案弄糊涂了,这个答案似乎有很高的票数: 当向BufferedReader对象发出“read”指令时,它会使用FileReader对象从文件中读取数据。当给出指令时,FileReader对象一次读取2(或4)

  • 问题内容: 例如,我有一个文件,其内容为: 然后我使用以下代码读取“ defg”。 因为文件中有足够的数据,我可以这样吗?我可以假设仅当文件中没有足够的字节时,该方法才返回小于给定缓冲区限制的数字吗? 问题答案: 我可以假设仅当文件中没有足够的字节时,该方法才返回小于给定缓冲区限制的数字吗? Javadoc说: 读取可能无法填充缓冲区 并举例说明 返回读取的字节数,可能为零;如果通道已到达流末尾,

  • TensorFlow程序读取数据一共有3种方法: 供给数据(Feeding): 在TensorFlow程序运行的每一步, 让Python代码来供给数据。 从文件读取数据: 在TensorFlow图的起始, 让一个输入管线从文件中读取数据。 预加载数据: 在TensorFlow图中定义常量或变量来保存所有数据(仅适用于数据量比较小的情况)。 目录 数据读取 供给数据(Feeding) 从文件读取数据

  • 我有一个小问题与Android和IOS之间实现套接字连接。当我使用我的应用程序连接两个Android运行设备时,一切正常。但是当我必须从Iphone应用程序接收一些数据时,我的readStream函数被阻塞,我可以在另一个部分关闭套接字后接收所有数据,这样我就不能返回任何响应。以下是我用来听的: 这里是我用来将转换为的函数: Iphone/Android应用程序的工作原理如下: 首先,它创建Soc

  • ap.getSessionData(OPTION | keys | key, CALLBACK) 读取会话级数据。可用于页面间传递数据。 可直接传入一个数组作为 OPTION.keys,或直接传入一个字符串,作为 OPTION.keys 数组中的某一个 key。 OPTION 参数说明 名称 类型 必填 描述 keys String Array 是 要读取的数据的 key CALLBACK 参数说