WebSocket 通讯协定简介:比较 Polling、Long-Polling 与 Streaming 的运作原理

这里介绍 HTML5 的 WebSocket 概念,并且跟传统的即时性网页技术 Polling、Long-Polling 与 Streaming 做比较。

HTML5 的 WebSocket 是一种建立在单一 TCP 连线上的全双工(full-duplex)通讯管道,可以让网页应用程式与伺服器之间做即时性、双向的资料传递。

WebSocket 跟以往实作全双工的技术比起来,改进了非常多,不但减低网路频宽的使用,有降低了网路延迟的时间。(关于网路的频宽与延迟可参考这里

 

Polling、Long-Polling 与 Streaming

当使用者在浏览网页时,浏览器会传送一个 HTTP 请求到网页伺服器上,然后伺服器会根据这个请求将网页的内容传回给浏览器,但是在很多的情况下,使用者会需要看到最新的即时性资讯,例如观看股票市场行情、监控网路流量等等,而在以前使用者只能靠着重新载入网页才能获得最新的资讯,但是这样不但很浪费时间,也会占用很多不必要的网路资源,并不是一个好的方式。

针对这个问题,目前已经有发展出许多技术可以解决,例如轮询(polling)或 Comet 这类的伺服器端 push 技术,透过延迟 HTTP 回应的方式达到及时传递讯息的方法,而 Comet 这类的实作通常都是使用 JavaScript 配合长时间轮询(long-polling)或串流(streaming)来达成。

轮询(Polling)

轮询(polling)的做法是让浏览器每隔一段时间就自动送出一个 HTTP 请求给伺服器,获取最新的网页资料,这个做法是最老旧的方式,如果你已经事先知道伺服器上资料更新的频率或时间,那么就可以使用这样的方式让浏览器上的资料同步更新,但是在许多即时性的网页应用程式上,情况并不是这样,你通常不会知道伺服器上的资料何时会更新,在伺服器没有新资料时,浏览器如果也送出 HTTP 请求,就会造成浪费网路资源的状况。

长时间轮询(Long-Polling)

长时间轮询(long-polling)则是让伺服器在接收到浏览器所送出 HTTP 请求后,伺服器会等待一段时间,若在这段时间里面伺服器有新的资料,它就会把最新的资料传回给浏览器,如果等待的时间到了之后也没有新资料的话,就会送一个回应给浏览器,告知浏览器资料没有更新。

虽然长时间轮询可以减少产生原本轮询(polling)造成网路频宽浪费的状况,但是如果在资料更新很频繁的状况下,长时间轮询并不会比传统的轮询有效率,而且有时候资料量很大时,会造成连续的 polls 不断产生,反而会更糟糕。

串流(Streaming)

串流(streaming)是让伺服器在接收到浏览器所送出 HTTP 请求后,立即产生一个回应浏览器的连线,并且让这个连线持续一段时间不要中断,而伺服器在这段时间内如果有新的资料,就可以透过这个连线将资料马上传送给浏览器。

这个方式虽然不错,但是由于他是建立在 HTTP 协定上的一种传输机制,所以有可能会因为代理伺服器(proxy)或防火墙(firewall)将其中的资料存放在缓冲区中,造成资料回应上的延迟,因此许多使用串流的 Comet 实作会在侦测到有代理伺服器的状况时,改用长时间轮询的方式处理。另外透过 TLS(SSL)的连线也可以避免缓冲区的问题,但是这个方式除了设定麻烦之外,也会造成伺服器额外的负担。

以上这些即时性更新网页的技术都有使用到 HTTP 的请求与回应,所以在网路上传输的资料中,一定会包含 HTTP 的表头资讯,而这些资料其实不是必要的,多传输这些资料反而会造成网路延迟上升。

如果是全双工的连线的话,只需要一条就可以同时处理上传与下载的资料传输,而如果以半双工的 HTTP 协定要达到全双工的效果,大部份的实作方式都会开启两条连线,一条负责上传、另一条负责下载,但是这样的做法不但让整个系统更加复杂、难以维护,而且伺服器的负担也会增加。

下图中这个架构是一个使用半双工 HTTP 协定的 Comet 应用程式架构,而后端搭配一个 messaging broker 以 publish/subscribe 的方式提供及时的资料。

comet-apps
复杂的 Comet 网页应用程式架构

这个状况在你要扩充系统的规模时会更糟糕,使用 HTTP 来实作双向的资料传输是一件很麻烦的事情,在维护很容易出问题,扩充也会有困难,纵使你的使用者感觉这样即时性的网页应用程式很好用,但是使用这样的架构同时会让你的伺服器与网路承受很大的工作负载量。

WebSocket 通讯协定

WebSocket 是定义在 H​​TML5 标准中的一个新的网页传输方式,可在一条连线上提供全双工、双向的资料传输,在这样的标准下你可以很容易实作一个兼具可扩充性与即时性的网页应用程式。另外因为 WebSocket 提供浏览器一个原生(native)的 socket,所以直接解决了 Comet 架构很容易出错的问题,而在整个架构的复杂度上也会比传统的做法简单很多。

浏览器与伺服器之间若要建立一条 WebSocket 连线,在一开始的交握(handshake)阶段中,要先从 HTTP 协定升级为 WebSocket 协定,浏览器送出:

GET /chat HTTP / 1.1 
Host : server.example.com 
Upgrade : websocket 
Connection: Upgrade 
Sec-WebSocket-Key : dGhlIHNhbXBsZSBub25jZQ== 
Origin : http://example.com 
Sec-WebSocket-Protocol : chat, superchat 
Sec-WebSocket- Version : 13

而伺服器回应:

HTTP / 1.1 101 Switching Protocols
 Upgrade : websocket 
Connection : Upgrade 
Sec-WebSocket-Accept : s3pPLMBiTxaQ9kYGzzhZRbK+xOo= 
Sec-WebSocket-Protocol : chat

当连线用的 socket 建立之后,WebSocket 的 data frames 就可以在浏览器与伺服器之间以全双工的模式进行双向的传输,不管是文字或是二进位的资料都没问题。

WebSocket 的在将资料打包成 data frame 时,在最好的状况下只会多出 2 个位元组(bytes)。如果是文字的资料,每一个 frame 会以一个0x00这个位元组开头,最后以0xFF这个位元组结束,中间的部分就是 UTF-8 的文字资料,若是二进位的资料,就会以 length prefix 来判断。不管如何其资料量都会比传统的 HTTP 协定小很多。

这里只是简略说明 WebSocket 的通讯协定概念,更详细规范可以参考 RFC6455 的说明。

WebSocket 效能测试

在 WebSocket 的官方网站上实作了一个股票监控网页,比较了传统 Polling 与新的 WebSocket 的效能差异,以下是一些实际的测试数据报告。

首先是网路频宽(bandwidth)的比较,WebSocket 的架构所使用的网路频宽比传统的 Polling 小非常多。

poll-ws-compare

另外这个是网路延迟(latency)的比较,由于 WebSocket 在通讯协定上的改进,所以在网路延迟也会比传统 Polling 所使用的 HTTP 小很多。

latency-comparison

若要查看详细的实验设计与测试过程,可以参考 WebSocket 的官方网站

发表评论

电子邮件地址不会被公开。 必填项已用*标注