我对 HTTP 轮询,长轮询,HTTP 流和 WebSocket 的理解

我已经阅读了许多关于我的问题标题中的关键词的帖子,从中学到了很多东西。我读到的一些问题与具体的实现挑战有关,而其他问题侧重于一般概念。我只是想确保我理解了所有的概念以及为什么技术 X 比技术 Y 发明的原因等等。所以我们开始吧:

Http Polling: 基本上是 AJAX,使用 XmlHttpRequest。

Http Long Polling: AJAX 但是除非服务器有更新,否则服务器会保留响应,一旦服务器有更新,它就会发送响应,然后客户端就可以发送另一个请求。缺点是需要来回发送额外的头数据,从而导致额外的开销。

Http Streaming: 类似于长轮询,但是服务器用一个“ Transfer Encoding: chunked”头进行响应,因此我们不需要每次服务器发送一些数据时都发起一个新的请求(从而节省了额外的头开销)。这里的缺点是,我们必须“理解”并找出数据的结构,以区分服务器发送的多个块。

Java Applet,Flash,Silverlight: 它们提供了通过 tcp/ip 连接到套接字服务器的能力,但由于它们是插件,开发人员不想依赖它们。

WebSockets: 它们是新的 API,试图以下列方式解决上述方法的缺点:

  • WebSocket 相对于 JavaApplet、 Flash 或 Silverlight 等插件的唯一优势是,WebSocket 本身内置于浏览器中,不依赖于插件。
  • 与 http 流相比,WebSocket 的唯一优势是您不必费力“理解”和解析接收到的数据。
  • 与长轮询相比,WebSocket 的唯一优势是消除了额外的头大小以及为请求打开和关闭套接字连接。

我还遗漏了什么其他重大差异吗?我很抱歉,如果我重新问或合并许多问题已经在 SO 成为一个单一的问题,但我只是想让所有的信息,在那里的 SO 和网络上有关这些概念的完美意义。

谢谢!

48803 次浏览

HTTP 将客户端与服务器之间的连接数限制为2(尽管可以通过使用子域来减轻这一限制) ,而 IE 已经知道如何迫切地实施这一限制。Firefox 和 Chrome 允许更多(尽管我不记得我的头顶到底有多少)。这可能看起来不是一个大问题,但是如果您经常使用1个连接进行实时更新,那么所有其他请求都必须通过其他 HTTP 连接造成瓶颈。还有一个问题是,拥有更多来自客户端的开放连接会给服务器带来更多负载。

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

这里有更多的差异比那些你已经确定。

双工/方向:

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

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

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

跨来源支援:

  • WebSockets: 是的
  • 插件网络: 通过策略请求的 Flash (不确定其他)
  • HTTP * (一些最近的支持)

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

  • WebSockets: 是的
  • 插件联网: 不支持 Flash (需要跨 ExternalInterface 的 URL 编码)
  • HTTP * : 最近启用二进制类型支持的建议

降低效率的带宽:

  • 插件联网: 除了最初的策略请求,Flash 套接字是原始的
  • WebSockets: 连接设置握手和每帧几个字节
  • HTTP 流(重用服务器连接)
  • HTTP 长轮询: 每条消息的连接
  • HTTP 轮询: 每条消息的连接 + 无数据消息

移动设备支持:

  • WebSocket: iOS 4.2及以上版本。一些 Android 通过 Flash 模拟或使用 安卓版火狐Android 版谷歌 Chrome 浏览器,这两者都提供了本地 WebSocket 支持。
  • 插件网络: 一些 Android 操作系统,不在 iOS 上
  • HTTP * : 大部分是的

Javascript 使用复杂度(从最简单到最复杂)。

  • WebSockets
  • HTTP 民意测验
  • 插件网络
  • HTTP 长轮询,流媒体

还要注意,有一个名为 服务器发送的事件的 W3C 提案用于标准化 HTTP 流。目前,它还处于相当早期的发展阶段,旨在提供一个标准的 Javascript API,其简单程度可与 WebSocket 相媲美。

其他人的一些很好的答案涵盖了很多领域。这里有一点额外的。

WebSocket 相对于 JavaApplet、 Flash 或 Silverlight 等插件的唯一优势是,WebSocket 本身内置于浏览器中,不依赖于插件。

如果这意味着您可以使用 JavaApplet、 Flash 或 Silverlight 来建立套接字连接,那么是的,这是可能的。然而,由于这些限制,您不会在现实世界中经常看到这种情况。

例如,中介可以并且确实关闭了该流量。WebSocket 标准被设计为与现有的 HTTP 基础设施兼容,因此不太容易受到防火墙和代理等中介的干扰。

此外,WebSocket 可以使用端口80和443而不需要专用端口,这也要感谢协议设计尽可能与现有 HTTP 基础设施兼容。

这些套接字替代品(Java、 Flash 和 Silverlight)很难在跨源架构中安全使用。因此,人们往往试图使用他们的跨来源将容忍不安全感,而不是去努力做到这一点安全。

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

简而言之,使用 Java、 Flash 或 Silverlight 进行套接字连接的问题已经够多了,以至于你不会经常看到它被部署在严肃的体系结构中。Flash 和 Java 拥有这种能力可能已经至少10年了,但它并不普遍。

WebSocket 标准能够从一种新的方法开始,记住这些限制,并希望从中吸取一些教训。

一些 WebSocket 实现在无法建立 WebSocket 连接时使用 Flash (或者可能是 Silverlight 和/或 Java)作为后备(例如在旧浏览器中运行或中介干扰时)。

虽然这些情况下的某种后备策略是明智的,甚至是必要的,但是大多数使用 Flash 等的用户都会遇到上面描述的缺点。不一定非要这样——有一些变通方法可以使用 Flash、 Silverlight 等实现安全的跨源连接——但大多数实现都不会这样做,因为这并不容易。

例如,如果您依赖于 WebSocket 进行跨原点连接,那么这种方法就可以很好地工作。但是如果你运行在一个旧的浏览器或者防火墙/代理服务器上,并且依赖于 Flash,比如说,作为你的退路,你会发现很难做同样的跨源连接。当然,除非你不在乎安全问题。

这意味着很难有一个单一的统一体系结构来适用于本机和非本机连接,除非您准备投入大量工作或者使用一个已经做得很好的框架。在理想的体系结构中,您不会注意到连接是否是本机的; 您的安全设置在这两种情况下都能正常工作; 您的集群设置仍能正常工作; 您的容量规划仍能正常工作; 等等。

与 http 流相比,WebSocket 的唯一优势是您不必费力“理解”和解析接收到的数据。

这并不像打开一个 HTTP 流,然后等待数据流数分钟、数小时或更长时间那么简单。不同的客户行为不同,你必须管理这一点。例如,一些客户机将缓冲数据,直到达到某个阈值时才将其释放给应用程序。更糟糕的是,在连接关闭之前,有些人不会将数据传递给应用程序。

因此,如果要向客户机发送多条消息,那么客户机应用程序可能要等到收到50条消息才会接收到数据。那不是太实时。

当 WebSocket 不可用时,HTTP 流可能是一个可行的替代方案,但它不是万能药。它需要一个良好的理解,以一种健壮的方式在现实世界的情况下工作在互联网的荒地上。

我还遗漏了什么其他重大差异吗?

还有一件事没有人提到,所以我要提一下。

WebSocket 协议被设计成一个用于更高级别协议的传输层。虽然您可以通过 WebSocket 连接直接发送 JSON 消息或其他东西,但它也可以携带标准或自定义协议。

例如,您可以通过 WebSocket 执行 AMQP 或 XMPP,人们已经这样做了。因此,客户机可以从 AMQP 代理接收消息,就好像它直接连接到代理本身一样(在某些情况下确实如此)。

或者,如果您有一个具有某种自定义协议的现有服务器,则可以通过 WebSocket 传输该协议,从而将后端服务器扩展到 Web。通常,已经锁定在企业中的现有应用程序可以使用 WebSocket 扩大其覆盖范围,而不必更改任何后端基础设施。

(当然,您希望能够安全地完成所有这些工作,因此需要与供应商或 WebSocket 提供商进行检查。)

有些人将 WebSocket 称为 Web 的 TCP。因为就像 TCP 传输更高级别的协议一样,WebSocket 也传输更高级别的协议,但是是以一种与 Web 基础设施兼容的方式。

因此,虽然通过 WebSocket 直接发送 JSON (或其他任何东西)消息总是可能的,但是还应该考虑现有的协议。因为对于你想做的许多事情,可能已经有一个协议来实现它。

我很抱歉,如果我重新问或合并许多问题已经在 SO 成为一个单一的问题,但我只是想让所有的信息,在那里的 SO 和网络上有关这些概念的完美意义。

这是一个很好的问题,答案都是非常有用的!

如果我可以问一件额外的事情: 我在某个地方看到一篇文章说,http 流也可以被代理缓存,而 websockets 不能。什么意思?

(StackOverflow 限制了评论响应的大小,所以我必须在这里回答而不是内联。)

有道理。为了理解这一点,考虑一个传统的 HTTP 场景... ... 假设一个浏览器打开了一个网页,因此它请求 http://example.com,比如说。服务器使用 HTTP 进行响应,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 服务器通信。这为最终用户提供了更快的响应,这总是很好的,但也意味着中心的负载更少。这可以转化为降低硬件成本、降低网络成本等等。所以这是件好事。

当在 Web 服务器上更新 logo.gif 时,问题就出现了。代理将继续为旧映像提供服务,而不知道有一个新映像。这会导致一系列的事情发生在到期之前,因此代理只能在映像“过期”之前缓存一小段时间,然后下一个请求通过代理传递到 Web 服务器,然后刷新代理的缓存。还有更先进的解决方案,中央服务器可以推出到已知的缓存,等等,事情可以变得相当复杂。

这和你的问题有什么关系?

您询问了 HTTP 流,其中服务器将 HTTP 流传输到客户机。但是流式 HTTP 就像普通的 HTTP 一样,只不过你不会停止发送数据。如果 Web 服务器提供一个图像,它将 HTTP 发送到最终结束的客户端: 您已经发送了整个图像。如果你想发送数据,它是完全一样的,但服务器只是发送了很长时间(就像一个巨大的图像,说) ,甚至从来没有完成。

从代理的角度来看,它无法区分静态资源(如图像)的 HTTP 和 HTTP 流中的数据。在这两种情况下,客户机都向服务器发出了请求。代理记住了那个请求和响应。下一次请求出现时,代理将提供相同的响应。

因此,如果您的客户机请求股票价格,并得到响应,那么下一个客户机可能会发出相同的请求并获得缓存数据。也许不是你想要的!如果你要求股票价格,你想要最新的数据,对不对?

所以这是个问题。

确实有一些技巧和变通方法可以处理这样的问题。显然,您可以让 HTTP 流工作,因为它现在正在使用。对于终端用户来说,这一切都是透明的,但是开发和维护这些架构的人员必须跨越重重障碍,付出代价。它导致体系结构过于复杂,这意味着更多的维护、更多的硬件、更多的复杂性和更高的成本。这也意味着当开发人员应该只关注应用程序、 GUI 和业务逻辑时,他们通常不得不关心一些不应该关心的事情——他们不应该关心底层的通信。