【问题标题】:WebSockets protocol vs HTTPWebSockets 协议与 HTTP
【发布时间】:2013-01-20 03:35:06
【问题描述】:

关于 WebSocket 和 HTTP 的博客和讨论很多,很多开发者和网站都大力提倡 WebSockets,但我还是不明白为什么。

例如(WebSocket爱好者的说法):

HTML5 Web Sockets 代表了 Web 通信的下一次发展——全双工、双向通信通道,通过 Web 上的单个套接字运行。 - websocket.org

HTTP 支持流式传输:请求正文流式传输(您在上传大文件时使用它)和响应正文流式传输。

在与 WebSocket 建立连接期间,客户端和服务器每帧交换数据,每帧 2 个字节,而进行连续轮询时的 HTTP 标头为 8 KB。

为什么这 2 个字节不包括 TCP 和 TCP 协议的开销?

GET /about.html HTTP/1.1
Host: example.org

这是约 48 字节的 HTTP 标头。

HTTP 分块编码 - Chunked transfer encoding:

23
This is the data in the first chunk
1A
and this is the second one
3
con
8
sequence
0
  • 因此,每个块的开销并不大。

另外,两种协议都通过 TCP 工作,因此所有与长连接的 TCP 问题仍然存在。

问题:

  1. 为什么 WebSockets 协议更好?
  2. 为什么实施它而不是更新 HTTP 协议?

【问题讨论】:

  • 你有什么问题?
  • @Jonas,1)为什么 websockets 协议更好? 2)为什么它被实施而不是更新http协议? 3) 为什么 websockets 如此推广?
  • @JoachimPileborg,对于桌面应用程序,您也可以使用 TCP 套接字或 http;并且您必须使用 WebRTC 为网站进行浏览器到浏览器的通信
  • @4esn0k,WS 并不是更好,它们对于某些特定任务是不同的并且更好。 3) 这是人们应该意识到并为 Web 开辟新可能性的新功能
  • @JoachimPileborg:错了,Websockets 是一种客户端服务器技术,而不是 P2P。

标签: ajax http websocket comet


【解决方案1】:

您似乎认为 WebSocket 是 HTTP 的替代品。它不是。这是一个扩展。

WebSockets 的主要用例是在 Web 浏览器中运行并从服务器接收实时数据的 Javascript 应用程序。游戏就是一个很好的例子。

在 WebSockets 之前,JavaScript 应用程序与服务器交互的唯一方法是通过 XmlHttpRequest。但是这些有一个主要缺点:除非客户端明确请求,否则服务器无法发送数据。

但是新的 WebSocket 功能允许服务器随时发送数据。这允许以低得多的延迟实现基于浏览器的游戏,而无需使用 AJAX 长轮询或浏览器插件等丑陋的黑客攻击。

那么为什么不使用普通 HTTP 处理流式请求和响应

在对另一个答案的评论中,您建议只异步流式传输客户端请求和响应正文。

事实上,WebSockets 基本上就是这样。从客户端打开 WebSocket 连接的尝试一开始看起来像一个 HTTP 请求,但标头中的一个特殊指令 (Upgrade: websocket) 告诉服务器以这种异步模式开始通信。 First drafts of the WebSocket protocol 仅此而已,还有一些握手以确保服务器真正理解客户端想要异步通信。但后来意识到代理服务器会因此而感到困惑,因为它们习惯于 HTTP 的通常请求/响应模型。发现了针对代理服务器的 potential attack scenario。为了防止这种情况发生,有必要让 WebSocket 流量看起来不像任何正常的 HTTP 流量。这就是 the final version of the protocol 中引入屏蔽键的原因。

【讨论】:

  • >> 除非客户端明确请求,否则服务器无法发送数据。 Web 浏览器应该启动 WebSockets 连接...与 XMLHttpRequest 相同
  • @4esn0k 浏览器确实启动了 websocket 连接。但建立后,双方可以随时发送数据。 XmlHttpRequest 不是这种情况。
  • 为什么 HTTP 不可能做到这一点?
  • @Philipp,游戏是 WebSocket 大放异彩的一个很好的例子。但是,它不是来自您获得最大胜利的服务器的实时数据。使用 HTTP 流式传输/长期保持的连接,您可以获得几乎一样好的服务器-> 客户端延迟。并且对于长期持有的请求,只要有数据,服务器就可以有效地发送,因为客户端已经发送了请求,并且服务器“持有请求”直到它有数据。 WebSockets 最大的优势在于客户端->服务器延迟(因此是往返)。客户端能够在没有请求开销的情况下随时发送是真正的关键。
  • @Philipp,另一个注意事项:除了 XMLHttpRequest 和 WebSockets 之外,还有其他方法可以让 JavaScript 与服务器交互,包括隐藏的 iframe 和长轮询脚本标签。有关详细信息,请参阅 Comet *页面:en.wikipedia.org/wiki/Comet_(programming)
【解决方案2】:

1) 为什么 WebSockets 协议更好?

WebSockets 更适合涉及低延迟通信的情况,尤其是对于客户端到服务器消息的低延迟。对于服务器到客户端的数据,您可以使用长期连接和分块传输获得相当低的延迟。但是,这对客户端到服务器的延迟没有帮助,因为需要为每个客户端到服务器的消息建立新的连接。

对于现实世界的 HTTP 浏览器连接,您的 48 字节 HTTP 握手是不现实的,因为请求中通常会发送数千字节的数据(双向),包括许多标头和 cookie 数据。以下是使用 Chrome 的请求/响应示例:

示例请求(2800 字节包括 cookie 数据,490 字节不包括 cookie 数据):

GET / HTTP/1.1
Host: www.cnn.com
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.68 Safari/537.17
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: [[[2428 byte of cookie data]]]

示例响应(355 字节):

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 13 Feb 2013 18:56:27 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: CG=US:TX:Arlington; path=/
Last-Modified: Wed, 13 Feb 2013 18:55:22 GMT
Vary: Accept-Encoding
Cache-Control: max-age=60, private
Expires: Wed, 13 Feb 2013 18:56:54 GMT
Content-Encoding: gzip

HTTP 和 WebSocket 都具有相同大小的初始连接握手,但是对于 WebSocket 连接,初始握手只执行一次,然后小消息只有 6 个字节的开销(2 个用于标头,4 个用于掩码值)。延迟开销不是来自标头的大小,而是来自解析/处理/存储这些标头的逻辑。此外,TCP 连接建立延迟可能是比每个请求的大小或处理时间更大的因素。

2) 为什么要实现它而不是更新 HTTP 协议?

正在努力重新设计 HTTP 协议以实现更好的性能和更低的延迟,例如 SPDYHTTP 2.0QUIC。这将改善普通 HTTP 请求的情况,但 WebSockets 和/或 WebRTC DataChannel 的客户端到服务器数据传输的延迟很可能仍然低于 HTTP 协议(​​或者它将用于看起来很像 WebSockets 的模式反正)。

更新

这是一个思考网络协议的框架:

  • TCP:低层、双向、全双工、保证顺序的传输层。不支持浏览器(通过插件/Flash 除外)。

  • HTTP 1.0:基于 TCP 的请求-响应传输协议。客户端发出一个完整的请求,服务器给出一个完整的响应,然后关闭连接。请求方法(GET、POST、HEAD)对服务器上的资源具有特定的事务意义。

  • HTTP 1.1:保持 HTTP 1.0 的请求-响应性质,但允许连接对多个完整请求/完整响应(每个请求一个响应)保持打开状态。请求和响应中仍有完整的标头,但连接被重用且未关闭。 HTTP 1.1 还添加了一些额外的请求方法(OPTIONS、PUT、DELETE、TRACE、CONNECT),它们也具有特定的事务含义。然而,正如 HTTP 2.0 草案提案的 introduction 中所述,HTTP 1.1 管道并未广泛部署,因此这极大地限制了 HTTP 1.1 在解决浏览器和服务器之间延迟方面的实用性。

  • 长轮询:对 HTTP(1.0 或 1.1)的一种“破解”,其中服务器不会立即响应(或仅使用标头部分响应)客户端请求。在服务器响应之后,客户端立即发送一个新请求(如果通过 HTTP 1.1,则使用相同的连接)。

  • HTTP 流式传输:允许服务器向单个客户端请求发送多个响应的多种技术(多部分/分块响应)。 W3C 使用text/event-stream MIME 类型将其标准化为Server-Sent Events。浏览器 API(与 WebSocket API 非常相似)称为 EventSource API。

  • Comet/服务器推送:这是一个涵盖长轮询和 HTTP 流的总称。 Comet 库通常支持多种技术,以尝试最大化跨浏览器和跨服务器支持。

  • WebSockets:基于 TCP 的传输层,使用 HTTP 友好的升级握手。与作为流传输的 TCP 不同,WebSockets 是基于消息的传输:消息在线路上进行分隔,并在交付给应用程序之前完整地重新组装。 WebSocket 连接是双向的、全双工的和长寿命的。在初始握手请求/响应之后,没有事务语义,并且每条消息的开销很小。客户端和服务器可以随时发送消息,并且必须异步处理消息接收。

  • SPDY:Google 发起的一项提议,使用更高效的有线协议扩展 HTTP,但保留所有 HTTP 语义(请求/响应、cookie、编码)。 SPDY 引入了一种新的帧格式(以长度为前缀的帧),并指定了一种将 HTTP 请求/响应对分层到新的帧层上的方法。可以压缩标头,并且可以在建立连接后发送新的标头。在浏览器和服务器中有 SPDY 的实际实现。

  • HTTP 2.0:与 SPDY 具有相似的目标:减少 HTTP 延迟和开销,同时保留 HTTP 语义。当前草案源自 SPDY,定义了升级握手和数据帧,与用于握手和帧的 WebSocket 标准非常相似。另一个 HTTP 2.0 草案提案 (httpbis-speed-mobility) 实际上将 WebSockets 用于传输层,并将 SPDY 多路复用和 HTTP 映射添加为 WebSocket 扩展(WebSocket 扩展在握手期间协商)。

  • WebRTC/CU-WebRTC:建议允许浏览器之间的点对点连接。这可以实现更低的平均和最大延迟通信,因为底层传输是 SDP/数据报而不是 TCP。这允许无序传送数据包/消息,从而避免 TCP 延迟峰值问题,该问题是由丢弃的数据包导致延迟所有后续数据包的传送(以保证按顺序传送)。

  • QUIC:是一种实验性协议,旨在减少与 TCP 相比的 Web 延迟。从表面上看,QUIC 与在 UDP 上实现的 TCP+TLS+SPDY 非常相似。 QUIC 提供相当于 HTTP/2 的多路复用和流量控制,相当于 TLS 的安全性,以及相当于 TCP 的连接语义、可靠性和拥塞控制。由于 TCP 是在操作系统内核和中间盒固件中实现的,因此对 TCP 进行重大更改几乎是不可能的。然而,由于 QUIC 是建立在 UDP 之上的,它没有这样的限制。 QUIC 针对 HTTP/2 语义进行了设计和优化。

参考文献

HTTP

服务器发送事件

WebSockets

SPDY

HTTP 2.0

WebRTC

QUIC

【讨论】:

  • >>但是,这对客户端到服务器的延迟没有帮助,这需要为每个客户端到服务器的消息建立新的连接。 - 响应体的流式传输呢?我知道,XMLHttpRequest API 不允许这样做,但它是存在的。通过流式传输到服务器,您可以从客户端流式传输。
  • @Philipp,他问了一个我一直想彻底研究和记录的问题。 WebSockets 与其他基于 HTTP 的机制的问题经常出现,但现在有一个很好的链接参考。但是,是的,提问者似乎确实在寻找证据来支持关于 WebSockets 与 HTTP 的先入为主的观念,特别是因为他从未选择过答案,也没有授予赏金。
  • @WardC caniuse.com 提供浏览器兼容性信息(包括移动设备)。
  • 我记得听说 websocket 使用大量带宽来保持连接处于活动状态。这是真的吗?
  • @www139,不,在 WebSocket 协议级别,连接保持打开状态,直到一侧或另一侧关闭连接。您可能还需要担心 TCP 超时(任何基于 TCP 的协议都存在问题),但每分钟或每两分钟的任何类型的流量都会保持连接打开。事实上,WebSocket 协议定义指定了一个 ping/pong 帧类型,尽管即使没有它,您也可以发送一个字节(加上两个字节的标头)并保持连接打开。每几分钟 2-3 个字节根本不会对带宽产生重大影响。
【解决方案3】:

对于 TL;DR,这里有 2 美分和一个更简单的版本供您提问:

  1. WebSockets 通过 HTTP 提供了这些好处:

    • 在连接期间的持久状态连接
    • 低延迟:服务器/客户端之间的近实时通信,因为没有按照 HTTP 要求为每个请求重新建立连接的开销。
    • 全双工:服务器和客户端可以同时发送/接收
  2. WebSocket 和 HTTP 协议旨在解决不同的问题,即WebSocket 旨在改善双向通信,而 HTTP 被设计为无状态,使用请求/响应模型进行分发。除了出于遗留原因(防火墙/代理渗透)共享端口之外,没有太多共同点将它们组合成一个协议。

【讨论】:

  • 重要的是,您在比较 (Y) 中提到了有状态和无状态一词
【解决方案4】:

其他答案似乎没有触及这里的一个关键方面,那就是您没有提到需要支持 Web 浏览器作为客户端。上述普通 HTTP 的大部分限制都假设您将使用浏览器/JS 实现。

HTTP协议完全能够进行全双工通信;让客户端执行带有分块编码传输的 POST 并且服务器返回带有分块编码主体的响应是合法的。这会将标头开销删除到仅在初始化时。

因此,如果您正在寻找的是全双工、控制客户端和服务器,并且对 WebSockets 的额外框架/功能不感兴趣,那么我认为 HTTP 是一种更简单的方法,具有更低的延迟/CPU(虽然延迟实际上只会在微秒或更少的时间内有所不同)。

【讨论】:

    【解决方案5】:

    为什么 WebSockets 协议更好?

    我认为我们不能像谁更好那样将它们并排比较。这不会是一个公平的比较,因为它们正在解决两个不同的问题。他们的要求不同。这就像将苹果与橙子进行比较。它们是不同的。

    HTTP 是一种请求-响应协议。客户端(浏览器)想要一些东西,服务器给它。那是。如果客户端想要的数据很大,服务器可能会发送流数据以避免不必要的缓冲区问题。这里的主要要求或问题是如何从客户端发出请求以及如何响应他们请求的资源(超文本)。这就是 HTTP 的亮点。

    在 HTTP 中,只有客户端请求。服务器只响应。

    WebSocket 不是只有客户端才能请求的请求-响应协议。它是一个套接字(非常类似于 TCP 套接字)。意味着一旦连接打开,任何一方都可以发送数据,直到下划线的 TCP 连接关闭。它就像一个普通的插座。与 TCP 套接字的唯一区别是 WebSocket 可以在 Web 上使用。在网络上,我们对普通套接字有很多限制。大多数防火墙会阻止 HTTP 使用的 80 和 433 以外的其他端口。代理和中介也会有问题。因此,为了使协议更容易部署到现有的基础设施 WebSocket 使用 HTTP 握手来升级。这意味着当第一次连接要打开时,客户端发送一个 HTTP 请求告诉服务器说“那不是 HTTP 请求,请升级到 WebSocket 协议”。

    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    

    一旦服务器理解请求并升级到 WebSocket 协议,则不再应用任何 HTTP 协议。

    所以我的回答是 没有一个比另一个更好。它们完全不同。

    为什么要实现它而不是更新 HTTP 协议?

    好吧,我们也可以使用 HTTP 的名称制作所有内容。但是我们可以吗?如果它们是两个不同的东西,我会更喜欢两个不同的名字。希克森和Michael Carter 也是如此。

    【讨论】:

      【解决方案6】:

      常规 REST API 使用 HTTP 作为通信的底层协议,它遵循请求和响应范式,这意味着通信涉及客户端从服务器请求一些数据或资源,然后服务器响应该客户端。但是,HTTP 是一种无状态协议,因此每个请求-响应周期最终都必须重复标头和元数据信息。在频繁重复的请求-响应周期的情况下,这会导致额外的延迟。

      使用 WebSockets,虽然通信仍以初始 HTTP 握手开始,但它会进一步升级以遵循 WebSockets 协议(即,如果服务器和客户端都符合该协议,因为并非所有实体都支持 WebSockets 协议) .

      现在使用 WebSockets,可以在客户端和服务器之间建立全双工和持久连接。这意味着,与请求和响应不同,只要应用程序正在运行,连接就会保持打开状态(即它是持久的),并且由于它是全双工的,因此可以进行双向同时通信,即现在服务器能够当新数据(客户感兴趣的)可用时,启动通信并将一些数据“推送”给客户。

      WebSockets 协议是有状态的,允许您实现发布-订阅(或发布/订阅)消息传递模式,这是实时技术中使用的主要概念,您能够以服务器的形式获取新的更新无需客户端重复请求(刷新页面)即可推送。此类应用的示例包括优步汽车的位置跟踪、推送通知、实时更新股票市场价格、聊天、多人游戏、实时在线协作工具等。

      您可以查看有关 Websockets 的深入研究文章,该文章解释了该协议的历史、它是如何形成的、它的用途以及如何自己实现它。

      这是我所做的关于 WebSockets 的演示视频以及它们与使用常规 REST API 的不同之处:Standardisation and leveraging the exponential rise in data streaming

      【讨论】:

      • 非常感谢@Shrushtika 的清晰解释。