日期:2014-05-20  浏览次数:20768 次

关于DataInputStream.read(byte[])阻塞和非阻塞
翻开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) 或抛出异常之前,此方法将一直阻塞

谁能帮忙解释,指导一下呢?

------解决方案--------------------
没遇见过这种情况
------解决方案--------------------
楼主对API理解的非常正确,现实中,也是这样的。

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

楼主再仔细查查,一般都是由我说的第二种情况引起的。
------解决方案--------------------
探讨
谢谢. 我仔细再看了jdk 描述..

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

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