翻开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) 或抛出异常之前,此方法将一直阻塞谁能帮忙解释,指导一下呢?

解决方案 »

  1.   

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

  2.   

    谢谢. 我仔细再看了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个字节之后他就认为自己可以解除阻塞跳出了...
      

  3.   

    每次读取的时候都是遍历数组赋值,只是前k下标的元素被覆盖……,后面length-k没有而已……
      

  4.   


    但是k为什么不能等于length呢?  这样的话,他的k是多长完全就不能由程序员控制了.难道还必须写 一个 for循环一个length吗?
      

  5.   

    楼主
    你看一下http://blog.csdn.net/yangjingyuan/article/details/6151234
    实际的网络环境与理想的网络环境是不一样的
      

  6.   

    额不知道是不是我没看懂,这个read方法返回的是本次阻塞获得的字节数量,这个应该就是API所说的k