用 HttpURLConnection 如何读取较大的数据流? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Marsss
V2EX    Android

用 HttpURLConnection 如何读取较大的数据流?

  •  
  •   Marsss 2017-12-19 16:13:55 +08:00 15319 次点击
    这是一个创建于 2861 天前的主题,其中的信息可能已经有所发展或是发生改变。
    临时开发的一个 app,Java 没来得及多看,基础比较弱,各位多指点。

    这样的,我试着用 HttpURLConnection 来向我的 flask 服务发起一个 http 请求,返回值,是一个比较大的 json 格式的数据


    只截取了一分,大概有几十 K 的大小,也不算是很大。然后就老是出现一个很奇怪的时候,debug 发现 app 这边接收了一小部分就报错了。


    SocketException: recvfrom failed: ECONNRESET 这个错误,网上出现的还不少,但是原因也比较多,我测试给他返回一个比较小的值时,就是正常的,那么我这边的原因也比较明确了,就是数据比较大,我接收的姿势可能太简单或者哪里没有设置对,导致数据没有接收完的时候,连接不明原因的断开了。

    这是代码


    开始以为是超时的问题,设置再长都没用。用浏览器直接访问这个连接,都没问题,而且速度非常快。所以,应该不是超时的问题。

    也试着换了 okhttp 这种比较新的包,仍然是会有这个问题,折腾几天了。
    6 条回复    2017-12-21 15:08:45 +08:00
    AlisaDestiny
        1
    AlisaDestiny  
       2017-12-19 17:15:48 +08:00
    http://blog.csdn.net/a859522265/article/details/7965971

    帮你找的。可能会对你有帮助。
    heyang
        2
    heyang  
       2017-12-19 17:32:05 +08:00
    https://tools.ietf.org/html/rfc7233
    拆分 - 合并, 记得校验
    TommyG
        3
    TommyG  
       2017-12-20 09:34:20 +08:00
    或许你应该将 InputStream 改为 BufferedInputStream .
    我觉得既然有几十 K 的大小,为什么不能当成一个文件进行下载?
    Marsss
        4
    Marsss  
    OP
       2017-12-20 11:18:41 +08:00
    @AlisaDestiny @heyang 谢谢二位,这些资料我也认真看过,设置 connection 为 close 并没有解决问题
    @TommyG 改成 BufferedInputStream 也是一样的问题,我试着将返回的数据缩短一些就都正常,数据量一旦超过某个值,debug 的时候就会看到 while 那里,只写了一部分就跳到异常了,异常那里显示的是连接被重置了。

    看起来就是数据量大了之后(实际上数据也就是几十 k,不算很大了),无法保持持久的数据读取。
    Marsss
        5
    Marsss  
    OP
       2017-12-21 11:05:59 +08:00
    野生码畜爬坑小记:

    又花了一天的时间来爬这个坑,暂时算是爬出来了。把一些东西写在这里,也许会有人需要参考。

    首先,我图中的代码不严谨:
    response.append(new String(b)) 这里由于 read(b)函数的特性,并不能保证每次都能填满 b 这个字节组,如果在某次循环中,read(b)只更新了 b 的一部分值,另外一部分值则还保留了上一次的值,这样 append 到 response 里,会出现问题。

    那么我们应该读到多少就 append 多少才行,改成这样:
    response.append(new String(b,0,len, charset))

    然而这个优化并没有解决我遇到的问题,我的程序在 debug 的时候依然还是只能读到一部分数据就跳异常了,我突然想到我之前使用的本机的浏览器测试访问正常的,那么直接使用模拟器的浏览器去访问呢,结果让我很意外,genymotion 模拟器自带的浏览器竟然也只读取到了一部分值,这 TM 至少说明了,也许我的代码并没有什么大毛病,可能是环境引起的问题。

    于是我在网上随便下载了一个雷电模拟器,用它自带的浏览器能正常获取到数据。于是直接使用这个雷电模拟器来 debug,这次终于正常了。。。看来被各种推荐的神器 genymotion 在 win 环境下也是可能存在一些问题的啊,MD,折腾了好几天了。

    另外,我觉得我这个帖子的问题可能问的有点不对,我其实并不需要知道怎么去用 httpurlconnection 读取一个较大的数据,不过我在搜索资料的过程中,可能对这个问题有一些思路,也顺便写在这里吧。

    我们其实可以在我们的服务端的 response 里面加一个 Accept-Ranges: bytes 栏,这样客户端就可以使用多线程分段请求的方式来读取这个大文件了,既解决了数据过大引起的读取差错,又提高了读取效率。详见 http 协议。

    看来还是不能太浮躁,心想着用了几天 python,Java 看都不看,撸起袖子就抄代码,终究还是要吃亏。

    就这样吧,谢谢各位。
    vjnjc
        6
    vjnjc  
       2017-12-21 15:08:45 +08:00
    HttpURLConnection 作为整个 android 系统的基础,我感觉是不会有这样的问题的。亲测至少下十几 MB 的图片都没问题,数据也下载过几百 KB 的数据,没遇到过问题,建议楼主使用框架化的 response
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2174 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 16:04 PVG 00:04 LAX 09:04 JFK 12:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86