我对HTTP轮询、长轮询、HTTP流和WebSockets的理解

153
我在SO和网络上阅读了很多帖子,涉及到我问题标题中的关键字,从中学到很多。我所读的一些问题涉及具体的实现挑战,而另一些则着重于一般性的概念。我只是想确保我理解所有这些概念以及技术X相对于技术Y的发明原因等推理。以下是具体内容:
HTTP轮询:基本上是AJAX,使用XmlHttpRequest。
HTTP长轮询:AJAX,但是服务器将保持响应,除非服务器有更新,一旦服务器有更新,它就会发送它,然后客户端可以发送另一个请求。缺点是需要来回发送附加的头数据,导致额外的开销。
HTTP流:类似于长轮询,但服务器会响应一个带有“传输编码:分块”的标头,因此我们不需要每次服务器发送一些数据时都初始化一个新请求 (因此节省了额外的头部开销)。这里的缺点是我们必须“理解”并找出数据的结构,以区分服务器发送的多个块。
Java Applet、Flash、Silverlight:它们提供连接到tcp/ip套接字服务器的能力,但由于它们是插件,因此开发人员不想依赖它们。
WebSockets:它们是新的API,试图通过以下方式解决上述方法的缺点:
  • WebSockets相对于Java Applets、Flash或Silverlight插件唯一的优点是WebSockets在浏览器中本地构建,不依赖于插件。
  • WebSockets相对于HTTP流的唯一优点是您无需努力理解和解析接收到的数据。
  • WebSockets相对于长轮询的唯一优点是消除了额外的头部大小以及打开和关闭套接字连接的请求。
我是否遗漏了其他重大的区别?如果我将许多SO上已有的问题重新组合成一个问题,并将它们结合起来,请见谅。但我只是想从SO和网络上的所有信息中完美地理解所有这些概念。
谢谢!

4
如果您不需要双向通信,也许可以考虑查看 "服务器发送事件"(Server-Sent Events)。 - leggetter
2
这是一个非常有用的问题。我认为如果有多个作者可以贡献一个答案,它可能会更有用。 - leggetter
1
使用HTTP流和长轮询需要第二个连接进行双向通信。一个长期存在的连接用于服务器->客户端的“推送”通信,第二个短暂存在的连接用于客户端->服务器的通信。这第二个连接用于设置和更改对数据的订阅等操作。因此,EventSource可以用于双向解决方案,并且实际上是从HTTP流和长轮询中产生的标准化解决方案。 - leggetter
1
你可能还想查看我写的这些技术分类:https://dev59.com/MWct5IYBdhLWcg3wc9Ig#12082152 - Alessandro Alinone
@leggetter,服务器发送事件似乎也是HTTP长轮询,而且这是我第一次听说它,你用过它或听说别人用过吗? - securecurve
显示剩余2条评论
4个回答

117

除了你所识别的差异之外,还有更多的差异。

Duplex / direction:

  • 单向:HTTP轮询、长轮询、流
  • 双向:WebSockets、插件网络

按延迟递增的顺序(大约):

  • WebSockets
  • 插件网络
  • HTTP流
  • HTTP长轮询
  • HTTP轮询

CORS(跨域支持):

  • WebSockets:是
  • 插件网络:通过策略请求使用Flash(不确定其他情况)
  • HTTP *(某些最新支持)

本机二进制数据(类型数组、blob):

  • WebSockets:是
  • 插件网络:Flash无法实现(需要在ExternalInterface上进行URL编码)
  • HTTP *:最近提议启用二进制类型支持

带宽由高到低:

  • 插件网络:Flash套接字除初始策略请求外为原始格式
  • WebSockets:连接设置握手和每个帧的少量字节
  • HTTP流(重复使用服务器连接)
  • HTTP长轮询:每个消息的连接
  • HTTP轮询:每个消息的连接+无数据消息

移动设备支持:

  • WebSocket:iOS4.2及以上版本。通过Flash模拟或使用Firefox for AndroidGoogle Chrome for Android可以在某些Android设备上提供本机WebSocket支持。
  • 插件网络:某些Android。不支持iOS
  • HTTP *:大多数是的

Javascript使用复杂性(从最简单到最复杂)。诚然,复杂度的衡量有点主观。

  • WebSockets
  • HTTP轮询
  • 插件网络
  • HTTP长轮询、流

还要注意,W3C正在提议将HTTP流标准化,称为服务器发送事件。目前它处于早期阶段,旨在提供具有可比较易用性的标准Javascript API,类似于WebSockets。


1
非常感谢您的回复,Kanaka。您能否告诉我为什么/如何HTTP流具有比WebSockets更高的延迟?也许可以用一个简单的例子来解释吗?非常感谢。 - Software Guy
2
@SoftwareGuy。有很多原因。在最近的浏览器上,您可以使用XMLHTTPRequest onprogress事件处理程序来通知数据。但规范规定50毫秒是最小的通知间隔。否则,您必须轮询响应数据。此外,客户端发送建立新的HTTP连接,从而显着增加往返延迟。此外,许多Web服务器在大约30秒后切断HTTP连接,这意味着您经常必须重新建立服务器推送连接。我在本地网络上看到了5-10毫秒的WebSocket往返延迟。HTTP流延迟可能为50毫秒或更长。 - kanaka
1
@leggetter 谢谢Phil,你的意思是通过http流将数据从客户端发送到服务器会导致开销吗?在http流中发送数据到服务器是否可能而不需要打开新连接?谢谢。 - Software Guy
指出每种方法的能源使用影响会很好。这可能需要测试,但实践经验告诉我,轮询比Web套接字更容易耗费电池电量。不确定这是否是我的经验的特殊性或一个好的数据点。 - Nathan
1
@Nathan 听起来是一个不错的硕士论文课题!当然,轮询会比事件驱动模型使系统更繁忙,但是功率节省到底有多少需要在不同规模下进行相当广泛的实证测试。 - kanaka
显示剩余3条评论

15

其他人提供了很多全面的答案,这里再补充一些。

WebSockets唯一的优势是与Java Applets、Flash或Silverlight等插件相比,WebSockets内置于浏览器中,不依赖插件。

如果你的意思是可以使用Java Applets、Flash或Silverlight来建立套接字连接,那么是可以的。但由于各种限制,你不会在现实世界中经常看到这种部署。

例如,中间人可以关闭这种流量。WebSocket标准旨在与现有的HTTP基础架构兼容,因此不太容易被防火墙和代理干扰。

此外,WebSocket可以使用端口80和443,而无需专用端口,这得益于协议设计的尽可能与现有的HTTP基础架构兼容。

那些套接字替代方案(Java、Flash和Silverlight)在跨域体系结构中使用时难以确保安全性。因此,人们常常会容忍不安全因素,而不是费力地确保其安全性。

它们还可能需要打开其他“非标准”端口(管理员不愿意这样做),或需要管理策略文件。

简而言之,使用Java、Flash或Silverlight进行套接字连接在实际架构中存在问题,因此你很少看到它们被广泛部署。Flash和Java可能已经具备了这种能力至少10年,但并不普遍。

WebSocket标准是从新的角度出发,并考虑到这些限制,希望能够从中吸取一些教训。

一些WebSocket实现在无法建立WebSocket连接时(例如在旧浏览器中运行或当中间人干扰时),会将Flash(或可能是Silverlight和/或Java)作为回退选择。

虽然对于这些情况有某种后备策略是明智的,甚至是必要的,但大多数使用Flash等的实现都会遭受上述缺点。它们可以通过一些变通方法来实现安全的跨域连接,但大多数实现不会这样做,因为这并不容易。

例如,如果您依赖WebSocket进行跨源连接,那么这将很好地工作。但是,如果您在旧浏览器或防火墙/代理干扰下运行,并依赖于Flash之类的后备方案,您将发现难以进行同样的跨源连接。当然,除非您不关心安全性。
这意味着要想拥有适用于本机和非本机连接的单一统一架构是困难的,除非您准备投入大量的工作或使用已经做得很好的框架。在理想的架构中,如果连接是本机的还是非本机的,您都不会注意到;您的安全设置将在两种情况下工作;您的集群设置仍将起作用;您的容量规划仍将保持;等等。
WebSockets相对于HTTP流的唯一优势在于,您无需努力“理解”和解析接收到的数据。
它不像打开HTTP流并坐等数据流动那么简单。不同的客户端的行为是不同的,您需要管理它们。例如,某些客户端将缓冲数据并仅在满足某个阈值时将其释放给应用程序。更糟糕的是,有些客户端直到连接关闭后才将数据传递给应用程序。
因此,如果您将多个消息发送到客户端,则可能要等到接收到50条消息的数据后,客户端应用才会接收到数据。这并不太实时。
虽然在WebSocket不可用时,HTTP流可能是一个可行的替代方案,但它不是万能药。在Web的恶劣环境下以真实世界的条件工作需要很好的理解。
还有其他显著的区别吗?
还有一件事情没有人提到,所以我来谈一下。
WebSocket协议旨在成为更高级别协议的传输层。虽然可以直接通过WebSocket连接发送JSON消息或其他内容,但它也可以携带标准或自定义协议。例如,你可以通过WebSocket执行AMQP或XMPP,许多人已经这样做了。因此,客户端可以像直接连接到代理一样接收来自AMQP代理的消息(在某些情况下确实如此)。
或者,如果您有一个具有某些自定义协议的现有服务器,则可以通过WebSocket传输该协议,从而将后端服务器扩展到Web。通常,已经被企业锁定的现有应用程序可以使用WebSocket来扩大其覆盖范围,而无需更改任何后端基础设施。
(自然地,您希望能够安全地执行所有这些操作,请与供应商或WebSocket提供商核实。)
一些人将WebSocket称为Web的TCP。因为就像TCP传输高级协议一样,WebSocket也是这样做的,但以一种与Web基础架构兼容的方式。
因此,虽然直接通过WebSocket发送JSON(或其他内容)消息总是可能的,但人们也应该考虑现有的协议。因为对于许多您想要执行的任务,可能已经存在可以完成它的协议。
“很抱歉,如果我正在重新问或将许多关于这些概念的问题合并成一个问题,但我只是想从SO和网络中获取的所有信息中获得完美的意义。”
这是一个很棒的问题,答案都非常有信息量!

非常感谢Robin提供的出色帮助和信息。如果我可以再问一件事:我在某篇文章中看到说http流可能也会被代理缓存,而websocket则不会。这是什么意思? - Software Guy
由于StackOverflow限制了响应评论的大小,我在下面给出了我的答案:https://dev59.com/gWcs5IYBdhLWcg3w0HOz#12569110 - Robin Zimmermann
@RobinZimmermann,你的回答是我最喜欢的。对于非常好的详细回答要点赞。 - securecurve

11
如果我可以再问一件事:我在某篇文章中看到说HTTP流也可以被代理缓存,而WebSocket则不能。这是什么意思?
这是个好问题。为了理解这一点,请考虑传统的HTTP场景...... 想象一下浏览器打开一个网页,它请求 http://example.com。服务器回复HTTP响应,其中包含页面的HTML。然后浏览器发现页面中有资源,因此开始请求CSS文件、JavaScript文件和图片,当然所有这些静态文件对于所有请求它们的客户端都是相同的。
一些代理会缓存静态资源,以便其他客户端的后续请求可以从代理获取这些静态资源,而不必返回到中央Web服务器获取它们。 这就是缓存,并且这是一种从中央服务卸载请求和处理的好策略。
所以,客户端1请求 http://example.com/images/logo.gif,该请求通过代理传递到中央Web服务器,该服务器提供logo.gif。当logo.gif经过代理时,代理将保存该图像并将其与地址http://example.com/images/logo.gif相关联。
当客户端2出现并且还请求 http://example.com/images/logo.gif,代理可以返回图像,而不需要与中央Web服务器进行任何通信。这为最终用户提供了更快的响应,这总是很好的,但它也意味着中心上的负载减少了。这可以转化为降低硬件成本、网络成本等。所以这是一件好事。问题出现在当logo.gif在web服务器上被更新时。代理将继续提供旧的图像,而不知道有新的图像存在。这就导致了一个关于过期的整个问题,因此代理只会在“过期”之前缓存图像一段时间,然后下一个请求通过代理发送到Web服务器,然后刷新代理的缓存。还有更高级的解决方案,其中一个中央服务器可以推送到已知的缓存等等,事情可以变得相当复杂。
这如何与你的问题联系起来?
你问到了HTTP流式传输,在此过程中,服务器向客户端流式传输HTTP。但是流式传输HTTP就像常规的HTTP一样,除了不停止发送数据。如果Web服务器提供图像,则它会向客户端发送HTTP,最终结束:您已经发送了整个图像。如果您要发送数据,则完全相同,但是服务器只是长时间发送(例如,就像是一个非常巨大的图像),甚至永远不会完成。
从代理的角度来看,它无法区分静态资源(例如图像)的HTTP或HTTP流数据。在这些情况下,客户端向服务器发出了请求。代理记住了该请求以及响应。下次该请求再次出现时,代理提供相同的响应。
因此,如果您的客户端请求股票价格,并获得响应,则下一个客户端可能会发出相同的请求并获取缓存的数据。这可能不是您想要的!如果您请求股票价格,您希望获得最新的数据,对吧?
所以这是个问题。
有一些技巧和解决方法来处理这样的问题,这是真的。显然,你可以使HTTP流式传输正常工作,因为它今天正在使用中。这对最终用户来说完全透明,但是开发和维护这些架构的人必须跳跃和支付代价。这会导致过于复杂的架构,意味着更多的维护、更多的硬件、更多的复杂性、更多的成本。它还意味着开发人员通常必须关注他们不应该关注的事情,当他们只应该专注于应用程序、GUI和业务逻辑时,他们不应该关注底层通信。

1
非常详细的回答,Robin,非常感谢!我真的很感激你的全面回复。我已经从这里所有优秀的人中学到了很多! :) - Software Guy

4

HTTP限制客户端与服务器之间的连接数为2(尽管可以通过使用子域名来缓解此问题),IE已知会积极执行此限制。 Firefox和Chrome允许更多连接(虽然我无法立即记住确切数量)。这似乎不是一个巨大的问题,但如果您始终使用1个连接进行实时更新,则所有其他请求都必须通过另一个HTTP连接瓶颈传输。而且,客户端有更多打开的连接会给服务器带来更多负载。

WebSockets是基于TCP协议的,因此不会受到HTTP级别连接限制的影响(但是,浏览器支持并不统一)。


谢谢thejuice,除了你指出的多个同时连接的问题之外,我的有关WebSockets的其他假设都是正确的吗? - Software Guy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接