关于DataInputStream.read(byte[])阻塞和非阻塞

chichenzhe 2012-03-16 11:54:34
翻开jdk,赫然写着:
public final int read(byte[] b) throws IOException
从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾 (end of file) 或抛出异常之前,此方法将一直阻塞

可是经过某些测试后我们惊奇的发现, 这个DataInputStream.read(byte[]) 并非阻塞的. 在一个长连接的socket通道上,读完数据之前 他就已经解除阻塞了,从而造成后面的报文发生粘包现象...而这个现象在PC上怎么都测试不出来, 一上真机的j2me环境就出了....

最后没办法. 我们采取 for循环一个固定length. 然后 一个字节 一个字节的读到 byte[]里.

但是问题是: 没道理啊. jdk上明明写着:检测到文件末尾 (end of file) 或抛出异常之前,此方法将一直阻塞

谁能帮忙解释,指导一下呢?
...全文
1168 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
cokepanm 2012-12-10
  • 打赏
  • 举报
回复
额。。。不知道是不是我没看懂,这个read方法返回的是本次阻塞获得的字节数量,这个应该就是API所说的k
ldaokun2006 2012-07-02
  • 打赏
  • 举报
回复
楼主
你看一下http://blog.csdn.net/yangjingyuan/article/details/6151234
实际的网络环境与理想的网络环境是不一样的
冰思雨 2012-03-16
  • 打赏
  • 举报
回复
楼主对API理解的非常正确,现实中,也是这样的。

可能是细节上面出了错误。
出现后面粘包现象,可能是由于,前面没有读取到足够的数据。
我们编程的时候,一般都用public final int read(byte b[], int off, int len) throws IOException
这个方法。
而楼主的那个方法,需要IO将参数缓冲区填满才返回,
这就有两种情况:
一:缓冲区的大小,比数据包小。
这样,实际上读取的是个半包,当然,一般后面程序会出现异常。
二:缓冲区的大小,比数据包大。
这样,实际上读取的是一个整包加一个半包。
这时,后面的程序,有可能只处理了那个整包的数据,缓冲区中的半包数据没有被处理,被丢弃了。
上述两种状况,都会引起后面的粘包现象。
所以,在知道包长度的情况下,使用我说的那个方法来读取数据,可以有效控制所读数据的长度。

楼主再仔细查查,一般都是由我说的第二种情况引起的。
jiakai0419 2012-03-16
  • 打赏
  • 举报
回复
没遇见过这种情况
chichenzhe 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 xpingping 的回复:]

引用 3 楼 chichenzhe 的回复:
谢谢. 我仔细再看了jdk 描述..

太隐晦了... "设 k 为实际读取的字节数" 原来他意思是: 这个read(byte[])的时候有可能读不到length那么长. 有可能发生length-k 个字节未被读取的现象发生.

也就是说读了k个字节之后他就认为自己可以解除阻塞跳出了...
每次读取的时候都是遍历数组赋值,只是前k下标的元……
[/Quote]

但是k为什么不能等于length呢? 这样的话,他的k是多长完全就不能由程序员控制了.

难道还必须写 一个 for循环一个length吗?
xpingping 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 chichenzhe 的回复:]
谢谢. 我仔细再看了jdk 描述..

太隐晦了... "设 k 为实际读取的字节数" 原来他意思是: 这个read(byte[])的时候有可能读不到length那么长. 有可能发生length-k 个字节未被读取的现象发生.

也就是说读了k个字节之后他就认为自己可以解除阻塞跳出了...[/Quote]
每次读取的时候都是遍历数组赋值,只是前k下标的元素被覆盖……,后面length-k没有而已……
chichenzhe 2012-03-16
  • 打赏
  • 举报
回复
谢谢. 我仔细再看了jdk 描述..

read
public int read(byte[] b)
throws IOException从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。
如果 b 的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。

将读取的第一个字节存储在元素 b[0] 中,下一个存储在 b[1] 中,依次类推。读取的字节数最多等于 b 的长度。设 k 为实际读取的字节数;这些字节将存储在 b[0] 到 b[k-1] 的元素中,不影响 b[k] 到 b[b.length-1] 的元素。

类 InputStream 的 read(b) 方法的效果等同于:

read(b, 0, b.length)
参数:
b - 存储读入数据的缓冲区。
返回:
读入缓冲区的总字节数;如果因为已经到达流末尾而不再有数据可用,则返回 -1。
抛出:
IOException - 如果不是因为流位于文件末尾而无法读取第一个字节;如果输入流已关闭;如果发生其他 I/O 错误。
NullPointerException - 如果 b 为 null。
另请参见:
read(byte[], int, int)


太隐晦了... "设 k 为实际读取的字节数" 原来他意思是: 这个read(byte[])的时候有可能读不到length那么长. 有可能发生length-k 个字节未被读取的现象发生.

也就是说读了k个字节之后他就认为自己可以解除阻塞跳出了...

62,612

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧