142

我在 SO 和网络上阅读了很多关于我的问题标题中的关键字的帖子,并从中学到了很多东西。我阅读的一些问题与具体的实施挑战有关,而另一些则侧重于一般概念。我只是想确保我理解所有概念以及为什么技术 X 比技术 Y 发明的原因等等。所以这里是:

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

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

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

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

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

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

我还缺少其他任何重大差异吗?如果我重新询问或将 SO 上的许多问题合并为一个问题,我很抱歉,但我只想从 SO 和网络上关于这些概念的所有信息中完全理解。

谢谢!

4

4 回答 4

108

与您确定的差异相比,差异更多。

双工/定向:

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

按照延迟增加的顺序(近似值):

  • 网络套接字
  • 插件网络
  • HTTP 流式传输
  • HTTP长轮询
  • HTTP 轮询

CORS(跨域支持):

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

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

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

降低效率的带宽:

  • 插件网络:Flash 套接字是原始的,除了初始策略请求
  • WebSockets:连接建立握手和每帧几个字节
  • HTTP 流式传输(重用服务器连接)
  • HTTP 长轮询:每条消息的连接
  • HTTP 轮询:每条消息都连接 + 没有数据消息

移动设备支持:

  • WebSocket:iOS 4.2 及更高版本。一些 Android 通过 Flash 仿真或使用Firefox for AndroidGoogle Chrome for Android,它们都提供原生 WebSocket 支持。
  • 插件网络:一些Android。不在 iOS 上
  • HTTP *:大部分是的

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

  • 网络套接字
  • HTTP 轮询
  • 插件网络
  • HTTP 长轮询,流式传输

另请注意,有一个 W3C 提议标准化 HTTP 流,称为Server-Sent Events。它目前还处于发展的早期阶段,旨在提供一个标准的 Javascript API,其简单性与 WebSockets 相当。

于 2012-09-23T20:57:25.277 回答
14

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

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

如果您的意思是您可以使用 Java Applet、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,例如,作为您的后备,您会发现很难进行相同的跨域连接。当然,除非您不关心安全性。

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

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 上的许多问题合并为一个问题,我很抱歉,但我只想从 SO 和网络上关于这些概念的所有信息中完全理解。

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

于 2012-09-24T06:47:41.987 回答
10

如果我可以再问一件事:我在某处的一篇文章中看到,http 流也可能被代理缓存,而 websockets 则没有。这意味着什么?

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

那是个很好的观点。要理解这一点,请考虑一个传统的 HTTP 场景......假设浏览器打开了一个网页,因此它请求http://example.com。服务器使用包含页面 HTML 的 HTTP 进行响应。然后浏览器看到页面中有资源,所以它开始请求 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 和业务逻辑时,他们通常不得不关心他们不应该关心的事情——他们不应该关心底层通信。

于 2012-09-24T16:26:33.097 回答
4

HTTP 将客户端与服务器的连接数限制为 2(尽管这可以通过使用子域来缓解),并且众所周知 IE 会急切地执行此操作。Firefox 和 Chrome 允许更多(虽然我不记得我的头顶到底有多少)。这似乎不是一个大问题,但如果您不断使用 1 个连接进行实时更新,则所有其他请求都必须通过其他 HTTP 连接成为瓶颈。还有一个问题是来自客户端的更多开放连接会给服务器带来更多负载。

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

于 2012-09-23T19:20:23.900 回答