移动网络环境下ReadBuffer的使用。

在过去的几年里支持过许多合作伙伴开发移动网络应用,发现移动网络下ReadBuffer方法的错误使用是一个常见问题。对ReadBuffer的错误使用会导致一些让开发人员觉得很奇怪的问题,如下载的zip文件无法解压,下载的音乐文件带杂音,自定义协议中的关键字节丢失等。而令人迷惑的是开发人员使用的代码都是在固定网络经受过实际检验的现成代码。 面对这种情况,很多开发人员都觉得无从下手,却不知道他们使用的代码其实隐含着一个大家忽略的问题。

  

首先来看看ReadBuffer方法,这个方法在多种语言上都有实现,大概的形式是这样的:

public int read(byte[] b,
                int off,
                int len)
         throws IOException

上面的代码样例是java版的,其它语言对该方法的定义也类似,下文以java代码为例。

 

ReadBuffer方法一般定义为InputStream的read方法,作用是从流中读取一定数量的字节到缓存中,在网络编程里是经常需要使用的。

使用这个方法容易出问题的地方是有关读取的长度,很多开发人员不仔细读API文档,使用时对读取长度没有清晰的认识,就很容易导致问题。

 

首先来看看API文档对三个参数的描述:

byte[] b  //b是目标缓存,容易理解

int off    // off是目标缓存中的偏移量,简单说就是从b数组的第几个元素开始写,一般会用ReadBuffer的人都是理解这个概念的。

int len  // len是希望读取的长度,注意“希望读取”这个描述。

 

再仔细看看该方法的描述,大意是:

该方法尝试从流中读取最多为len的字节流,实际读取字节数有可能小于len,最后真正的读取长度以int值返回。

 

也就是说该方法实际读取了多少字节需要检查返回值才知道,而很多开发人员使用该方法时直接认为该方法会读取len参数指定长度的字节。令问题变得诡异的就是实际使用中开发人员的这种假设经常是正确的,特别是len很小,而且网络速度很快的时候。

 

看看下面的代码,可能你也使用过:

  byte[] result= new byte[2];
  
  mySourceStream.read(result,0,2);
  
  byte a1=result[0];
  byte b1=result[1];



看上去好像是没有问题的,从流里读取两个字节,放在result中,然后第一个给变量a1,第二个给变量b1。后面开始使用a1和b1两个变量。

但是,如果read方法只读了一个字节呢? 按照API说明,该方法会尝试读取2个字节,但有可能只读取一个字节。这样的话,b1等于什么值就不确定了。

如果这个b1恰好就是自定义协议中的关键字节,如包长,那么你的程序就留下了一个很大的隐患。

 

这种程序拿到固网上单独测试100遍,有可能完全不出问题,甚至测试1000遍也不出问题。不过,将这个程序拿到移动网络中,出问题的几率就很大了。如果是移动网络中的一个长连接,那么出问题的可能性就几乎是100%了。

 

对ReadBuffer的不严谨使用有很多形式,带来的问题也就多种多样,如上面提到的下载的zip文件无法解压,音乐文件带杂音等。当开发人员在移动网络环境中遇到这些问题的时候,需要检查一下ReadBuffer的使用,不要因为代码在固网中没有问题就直接将问题的根源推给移动设备商或者是移动网络提供商。


 

 

你可能感兴趣的:(api,网络,网络应用,文档,音乐,byte)