iPad / iPhone上的HTTP字节范围协议客户端行为

我正在测试支持HTTP字节范围请求的HTTP servlet实现(由BalusC共享) 。

我发现不同的HTTP客户端之间存在一些特殊的差异,并且想知道我是否遗漏了任何东西。 我使用了> 2G mp4video文件进行测试,并使用Wireshark捕获数据包。 这大致是发生的事情:

  • 三星Galaxy SII:

    • 文件的HTTP GET请求到来,要求字节范围[0; ] [0; ]
    • 服务器响应,开始流式传输文件
    • 每个后续块在同一HTTP响应的范围内提供。 没有发送新的HTTP请求(除非video被快速转发到某个位置)。 流式代码块非常简单,它读取RandomAccessFile input并通过byte[] buffer写入OutputStream output

       while ((read = input.read(buffer)) > 0) { output.write(buffer, 0, read); } 
  • iPad 1
    • 文件的HTTP GET请求到来,要求字节范围[0; ] [0; ]
    • 服务器响应,开始流式传输文件
    • iPad获得一两块,然后单方面决定停止从服务器接受字节,并为文件的下一个块发出单独的GET请求 。 新的范围边界是例如[100, almost the end of the file] 。 video显示正常。
    • 从第2步开始重复循环。左边界始终向文件末尾移动。

我没有调查连接的确切方式。 可能是iPad停止发送TCP ACK数据包,我想这并不重要。

我的问题是,对于每个终止的连接,我得到java.net.SocketException: Broken pipe断开exception。 这不仅会污染日志(这是一个小问题/可解决的问题),但我相信这会影响性能,因为提高exception是非常昂贵的。 在观看简单video时,exception率约为1个exception/秒,但如果服务器有100个并发用户,那么JVM可能会花费大量时间来计算堆栈跟踪而不是实际工作。

我也使用iOS 6在iPhone上进行了测试,并且能够观察到与iPad 1相同的行为。重申一下,这不会发生在三星Android或我尝试的任何桌面浏览器上,包括桌面Mac上的Safari。

问题:

  • 这是iPad / iPhone的已知错误/function吗?
  • 这是一个解决方法吗?

IIRC,“断管”只是意味着另一方在关闭其读取结束后收到数据。

我能想到的最合理的事情是,它试图不浪费大量带宽下载永远不会被观看的video(也许他们已经与运营商达成一致,我怀疑这是“直播”限制背后的原因:

“超过10分钟的蜂窝网络上的video流内容必须使用HTTP直播流,并包括基准64 kbps纯音频HTTP直播流。”

限制下载的唯一另一种简单方法是停止read()并等待接收窗口填满,但这并不总是很容易(例如, NSURLConnection并不能让这很容易)。

如果你非常幸运,客户端将关闭其写入结束(这样服务器将read() EOF)并等待一段时间再关闭其读取结束。 在这种情况下,可以安全地假设客户端不再需要其余的下载。 RFC 2616有点模糊(似乎忘记了套接字只能在一个方向上关闭),但提到“优雅关闭”( 根据Microsoft的说法,关闭写入端并从读取端完成读取,直到超时通过),但也说

除非怀疑网络或客户端故障,否则服务器不应在传输响应的过程中关闭连接。

因此,如果您知道它是一个iDevice并且您读取EOF,那么服务器关闭套接字可能是安全的,只要您已经彻底测试它不会破坏任何内容 – 根据User-Agent改变HTTP行为就好像一个可怕的想法。

或者,不要在乎。 如果它是一个iDevice(它似乎不如改变HTTP行为那么糟糕),你可以进行UA嗅探并忽略exception。 exception开销几乎可以忽略不计,并且可能远低于将其打印到日志的开销。 每秒100个例外是没有的。 如果你不确定,请描述一下。

您也可以向Apple提交一个错误 ,但随着这些事情的发生, 网络行为并不是特别可疑 。

在iPhone上进行流式传输时,您需要发送Accept Ranges标头。 这可能会导致您的问题。 看看这篇文章

直接访问时播放MP4,但在iOS上通过PHP读取则不播放

首先,

花费大量时间来计算堆栈跟踪

不打算计算你是否打算调用get / printStackTrace()。 把它从日志中取出或抓住它并在某处避开它。

我有同样的问题,它也没有消失。 好吧,这些都是非常愚蠢的选择,但是您可以使用负载均衡器来接受连接,并将您的服务器tomcat或glassfish重定向到您正在使用的任何地方。 当我开始在AWS上使用ELB时,我观察到这种缺乏管道破坏的行为。 NGINX或Apache可以为您做一些前沿通信。

我这样说是因为即使操作系统也可能是因为操作系统上的JVM实现而导致JVM无法正常关闭TCP通信的原因。

回到我们的共同发现。 在Apple网站上查看此讨论 。 现在看来,这个问题导致iOS6在流式传输时消耗过多数据。

(用荷兰语,但这里报告的问题完全相同.Android做1请求,iOS做多个请求)

是时候用iOS6.0.1重新测试这些东西,看看它们是否确实修复了范围请求问题。

刚刚在我的iPod Touch第五代测试 – iOS6.0.1:范围请求仍然请求0-1,然后几次0完整文件,然后是更小的范围。 然而,它看起来仍然很混乱