为什么输入流以块的形式读取数据?

时间:2012-08-23 10:54:22

标签: java sockets network-programming inputstream

我正在尝试使用以下代码从网络套接字读取一些数据 -

Socket s = new Socket(address, 502);
response = new byte[1024];
InputStream is = s.getInputStream();
int count = is.read(response, 0, 100);

数据量不大。它总共是16个字节。但是read()语句不能一次读取所有数据。它只将8个字节的数据读入我的缓冲区。

为了读取数据,我必须多次调用read() -

Socket s = new Socket(address, 502);
response = new byte[1024];
InputStream is = s.getInputStream();
int count = is.read(response, 0, 100);
count += is.read(response, count, 100-count);

为什么会这样?为什么read()不能一次读取整个流?

请注意,数据并未逐渐到达。如果我在通过调用Thread.sleep(2000)读取数据之前等待2秒,则行为保持不变。

3 个答案:

答案 0 :(得分:7)

  

为什么read()不能一次读取整个流?

因为未指定这样做。见Javadoc。它会阻塞,直到至少有一个字节可用,然后返回1和所提供长度之间的一些数字,包括在内。

反过来,这是因为数据不一定一次到位。您无法控制TCP如何发送和接收数据。您有义务将其视为字节流。

答案 1 :(得分:1)

  

据我所知,它会阻止数据到达。 “这反过来是因为数据不一定一次到位。”为什么不是我的问题。

数据并不一定都是一次性到达,因为网络通常会将其分解为数据包。 IP是数据包交换协议。

  

TCP是否传输8字节的块?

可能,但可能不是。数据包大小取决于数据遍历的网络/网络,但典型的Internet数据包大小约为1500字节。

如果您一次获得8个字节,则您的数据要么通过具有异常小的数据包大小的网络,要么(更有可能)发送方一次发送8个字节的数据。第二种解释或多或少与你的其他评论所说的一致。

  

由于我明确指定100,一个比缓冲区中的数据大得多的数字不应该尝试读取直到至少100个字节?

没有。它没有指定以这种方式工作,并且它不起作用。您需要根据规范说明编写代码。


这可能与设备被“轮询”的方式有关。但是,如果不查看设备的规格(甚至不知道它究竟是什么),这只是猜测。

答案 2 :(得分:0)

也许数据逐渐到来不是因为你的阅读而是因为发件人。

发送者应该使用BufferedOutputStream(在中间)在发送之前制作大块(并且仅在需要时使用flush)。