V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Marsss
V2EX  ›  Android

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

  •  
  •   Marsss · 2017-12-19 16:13:55 +08:00 · 12737 次点击
    这是一个创建于 2561 天前的主题,其中的信息可能已经有所发展或是发生改变。
    临时开发的一个 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   ·   实用小工具   ·   1068 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 19:33 · PVG 03:33 · LAX 11:33 · JFK 14:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.