InputStream 中available 的使用

因为网络传输的非实时性,你就不能把你程序写成单次顺序执行的方式,因为,在你的程序去检查available的时候,实际上另一端可能还没有发送数据,或对方网络拥挤,要发给你的数据包还在队列中。所以你调用 available 会返回0。 

你看看别人写的程序,一般不是用异步框架,如:mina,就是用线程不断扫描IO流,就是出于这个原因。 

而且 available 返回的字节数也不一定就是对方实际发送数据的长度,因为,如果数据长度过大的话,在实际的网络发送过程中,会对数据进行分段,分多次发送,而 available  只返回本次的可用字节数,这就是我开始讲的第二点“网络传输的不连续性”。 

所以,你如果对网络游戏的网络数据包有研究的话,你会发现,他们一般都会将本次要传输的字节数,放到整个数据包的开头的某一段位置,如:WOW。也就是说要自己设计网络传输的数据结构来实现发送数据的长度,才是最可靠的。


先看看下面这段代码(有删节)

public static String send(String sendurl, String sendText) throws Exception {
   URL url = null;
   URLConnection uc = null;

//建立连接、输出数据等;

String strReceive = ""; 
   try {
    InputStream is = uc.getInputStream();

    DataInputStream in = new DataInputStream(is);
   
int blockLen = in.available();
    byte block[] = new byte[blockLen];
   
for (int readLen = -9999; readLen != -1;) {
      readLen = in.read(block);

      if (readLen != -1)
       strReceive = strReceive + new String(block);
     }
    is.close();
    in.close();
   } catch (IOException e) {
    logger.info("httpl接收错误1:" + e.getMessage());
   }
   return strReceive;
}

注意红色字体那几行。blockLen被用来创建一个字节数组block,block作为数据缓冲来读取inputstream里的数据。然后循环从inputstream中读取数据,写入block中。

考虑一种情况。如果网络阻塞了,inputstream已经打开,但是数据却还没有传输过来,会发生什么?

inputstream.available()方法返回的值是该inputstream在不被阻塞的情况下一次可以读取到的数据长度。如果数据还没有传输过来,那么这个inputstream势必会被阻塞,从而导致inputstream.available返回0。而对inputstream.read(byte[] b)而言,如果b的长度等于0,该方法将返回0。

回头看看这个循环体的结束条件,是readLen == -1时跳出。显然,上面提到的网络阻塞情况发生之后,代码将陷入这个死循环当中。

这是我们在工程应用中遇到的一个问题。由外包商提供的工具jar包中的这段代码,直接将我们的服务器拉进了死循环。

我们的解决方法,是将整个接收与发送的方法进行改写,使用了下面的这段代码:

   HttpClient client = new HttpClient();
    PostMethod method = new PostMethod(prpUrl);
    method.setRequestBody(sendstr);
    method.getParams().setParameter(
      HttpMethodParams.HTTP_CONTENT_CHARSET, "GBK");
    client.executeMethod(method);
    // rtnXml = method.getResponseBodyAsString();
    InputStream txtis = method.getResponseBodyAsStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(txtis));
    String tempbf;
    StringBuffer html = new StringBuffer(100);
    while ((tempbf = br.readLine()) != null) {
     html.append(tempbf);
    }
    rtnXml = html.toString();

    method.releaseConnection();

确确实实的,解决了问题。

如果仍然要采用原方法中手动打开输入流、建立缓冲区、循环读取数据的方法,那么不应该用available这个字段来作为缓冲区的初始长度。可以考虑手工设定一个固定值;或者读取http报文头的content-length属性值。最后的这种方式没有尝试过。



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值