2012-09-28 52 views
12

我正在测试支持HTTP byte range requestsHTTP servlet implementation (kindly shared by BalusC)iPad/iPhone上的HTTP字节范围协议客户端行为

我发现了不同的HTTP客户端之间的一些特殊的区别,并想知道我是否没有丢失任何东西。我为我的测试使用了> 2G mp4视频文件,并使用Wireshark捕获数据包。这大概会发生什么:

  • 三星Galaxy SII:

    • HTTP GET文件请求到来时,要求字节范围[0; <almost the end of the file>]
    • 服务器响应,开始流的文件
    • 每个后续块在相同的HTTP响应的范围内服务。没有新的HTTP请求被发送(除非视频被快速转发到某个位置)。该流的代码块是非常简单,它读取RandomAccessFile input,并通过byte[] buffer写入OutputStream output

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

我没有调查的连接究竟如何终止。这可能是iPad停止发送TCP ACK数据包,我想这并不重要。

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

我一直使用的是iOS 6还测试了这款iPhone和能够观察到相同的行为像iPad 1.刚重申,这一不会对三星的Android也没有任何桌面浏览器我都试过了,包括Safari上发生桌面Mac。

问题:

  • 这是iPad/iPhone的的知道是不是BUG /功能?
  • 有没有解决这个问题的方法?
+0

找到[由别人问的同一问题](https://groups.google.com/forum/#!msg/youtube-api-gdata/V6RU2h9afBg/ibaJ7yOHjBAJ)以及[另一个](http://stackoverflow.com/questions/6094556/mobile-safari-makes-multiple-video-requests),遗憾的是到目前为止没有有用的答案:( – mindas

回答

1

您需要发送一个接受范围头在iPhone上的流时。这可能会导致您的问题。看看这个帖子

MP4 plays when accessed directly, but not when read through PHP, on iOS

+0

感谢您的回答。事实上,我发送' Accept-Ranges:bytes' header,否则视频根本无法播放。任意数据流定位也可以,唯一的问题是终止连接。 – mindas

+0

不知道,我在该链接中使用了解决方案,它工作正常。怎么样连接Keep-Alive头? 只是使用Google,它看起来像一个可能与iOS无关的常见问题:http://mikeschubert.com/2006/08/03/javanetsocketex/ –

+0

解决方案有效,但我想了解为什么iPad/iPhone的行为与Android和桌面不同?如果这是一个数据库问题,它也会在其他地方失败,但现在它只对苹果移动设备失败。 – mindas

1

首先,

的时间花费负载只是计算堆栈跟踪

是不会计算,如果你是不是要去调用获取/的printStackTrace()。把它从日志中关掉或者抓住它并避开它。

我有同样的问题,也没有任何离开我。那么,这些是非常愚蠢的选择,但你可以使用一个负载均衡器来接受连接,并将你的服务器tomcat或glassfish重定向到你正在使用的任何地方。当我开始在AWS上使用ELB时,我发现这种缺乏断管行为。 NGINX或Apache可以为你做一些边防通信。

我这样说,因为即使是操作系统可为什么JVM不接受,因为JVM执行OS上的正确的TCP通信中断的原因。

+2

虽然它可能不计算符号,但在堆栈被覆盖之前需要保存计算堆栈跟踪所需的信息;我已经看到代码重写'Throwable.fillInStackTrace()'以避免这种开销(代码最终被重写为不在图像的每一行上引发异常)。 –

3

IIRC,“破管”仅仅意味着在另一侧接收的数据后,关闭它的读端。

我能想到的最合理的事情是,它试图不浪费大量的带宽下载视频,永远不会被监视(也许他们已经与运营商达成一致,我怀疑这是"live streaming" restriction背后的原因:

其他唯一的简单的方法来节流“视频流在蜂窝网络上超过10分钟必须使用HTTP实时流和包括基线64kbps的只有音频的HTTP直播流长。内容”下载是停止read() ing并等待接收窗口填满,但这并不总是很容易做到(例如,NSURLConnection实际上并不容易)。

如果您非常幸运,客户端将关闭它的写入端(例如服务器将为read() EOF)并稍等片刻,然后再关闭其读取端。在这种情况下,它可能安全的假设,客户端不再想要下载的其余部分。 RFC 2616有点朦胧(似乎忘了插座只能在一个方向被关闭),但提到了“正常关闭”(这according to Microsoft包括关闭写入侧和完成从读一边,直到超时通过读书),也称

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

所以,如果你知道这是一个的iDevice和阅读EOF,那么它可能是安全的服务器关闭套接字,前提是你已经彻底测试,它不会破坏任何东西—改变HTTP行为取决于用户代理看起来像一个可怕的想法。

或者,不在乎。你可以做U-A嗅探,如果它是一个iDevice(这看起来不像改变HTTP行为那么可怕),就会忽略异常。异常开销几乎可以忽略,并且可能远低于将其打印到日志的开销。每秒100个例外是没有的。如果您不确定,请对其进行配置。

你也可以file a bug with Apple,但是随着这些事情的发展,它不是particularly dubious network behaviour

+0

我认为我不同意你关于“浪费大量带宽”的观点;客户端可以简单地延迟TCP ACK以便稍后获取下一个块。至少它能做的是优雅地关闭连接。无论如何,谢谢你的回答 - 这是我所得到的最好的。我向您颁发了积分,但如果有人提供了更好的解释为什么iPad/iPhone行为被破坏(如果有的话),将保持这个问题的公开。 – mindas

+0

@mindas客户端*可能延迟ACK,但服务器仍然会继续发送数据包,直到发送窗口填满为止,再次,使用NSURLConnection完成这件事并不容易。再次,客户*可能*尝试“优雅的关闭”,但超时;没有更多的信息,很难说。 –

1

回到我们的共同发现。看看苹果网站上的this discussion。现在看来,这个问题导致iOS6在流式传输过程中消耗了太多数据。

(荷兰语版本,但完全相同的问题报告here。安卓做1个请求,iOS的做多请求)

时间重新测试这个东西与iOS6.0.1,看看他们是否确实固定范围请求问题。

刚刚在我的iPod Touch第五代 - iOS6.0.1上测试过:范围请求仍在请求0-1,然后是几个0-全文件,然后是较小的范围。然而它仍然看起来很凌乱

+0

感谢您分享此内容。根据我的理解,看起来他们已经承认这是其中一个应用程序(播客?)的问题,但不是浏览器。无论如何,如果您发现任何问题,请让我们张贴。我已经放弃了这个问题;-( – mindas

相关问题