2

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

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 秒,则行为保持不变。

4

3 回答 3

7

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

因为没有指定这样做。请参阅 Javadoc。它阻塞直到至少有一个字节可用,然后返回介于 1 和提供的长度之间的某个数字,包括 1 和所提供的长度。

这反过来又是因为数据不一定会一次性全部到达。您无法控制 TCP 如何发送和接收数据。您必须将其视为字节流。

于 2012-08-23T10:59:44.770 回答
1

我知道它会阻塞直到数据到达。“这反过来又是因为数据不一定会一次性全部到达。” 为什么不是我的问题。

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

TCP 是否传输 8 个字节的块?

可能,但可能不会。数据包大小取决于数据经过的网络/网络,但典型的互联网数据包大小约为 1500 字节。

如果您一次收到 8 个字节,则您的数据要么来自数据包大小异常小的网络,要么(更有可能)发送方一次发送 8 个字节的数据。第二个解释或多或少与您的其他评论所说的相吻合。

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

好吧,没有。它没有指定以这种方式工作,也不是那样工作的。您需要根据规范的内容编写代码。


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

于 2012-08-23T11:18:20.393 回答
0

也许数据逐渐到达不是因为您的阅读,而是因为发送者。

The sender should use a BufferedOutputStream (in the middle) to make big chunks before sending (and use flush only when it's needed).

于 2012-08-23T12:09:43.033 回答