最近小组在作一个智慧交通的项目,其中有个 “分享屏幕” 的功能,即一个 client 可以将本身当前的页面分享到另一个 client,针对这个需求,咱们利用了 WebSocket 技术,具体说是 Socket.IO。php
提到 WebSocket,我首先会想到 “及时通信” 和 “推送” 这类词。在 WebSocket 之前,不少网站经过其余方式来推送信息,下面咱们先看看之前的推送方式,这样,有比较才能看出 WebSocket 的优点。html
这种方式下,client 每隔一段时间都会向 server 发送 http 请求,服务器收到请求后,将最新的数据发回给 client。一开始必须经过提交表单的形式,这样的后果就是传输不少冗余的数据,浪费了带宽。后来 Ajax 出现,减小了传输数据量。程序员
如图所示,在 client 向 server 发送一个请求活动结束后,server 中的数据发生了改变,因此 client 向 server 发送的第二次请求中,server 会将最新的数据返回给 client。web
但这种方式也存在弊端。好比在某个时间段 server 没有更新数据,但 client 仍然每隔一段时间发送请求来询问,因此这段时间内的询问都是无效的,这样浪费了网络带宽。将发送请求的间隔时间加大会缓解这种浪费,但若是 server 更新数据很快时,这样又不能知足数据的实时性。服务器
鉴于(短)轮询的弊端,一种基于 HTTP 长链接的 “服务器推” 的技术被 hack 了出来,这种技术被命名为 Comet。其与(短)轮询主要区别就是,在轮询方式下,要想取得数据,必须首先发送请求,在实时性要求较高的状况下,只能增长向 server 请求的频率;而 Comet 则不一样,client 与 server 端保持一个长链接,只有数据发生改变时,server 才主动将数据推送给 client。Comet 又能够被细分为两种实现方式,一种是长轮询机制,一种是流技术。微信
client 向 server 发出请求,server 接收到请求后,server 并不必定当即发送回应给 client,而是看数据是否更新,若是数据已经更新了的话,那就当即将数据返回给 client;但若是数据没有更新,那就把这个请求保持住,等待有新的数据到来时,才将数据返回给 client。websocket
固然了,若是 server 的数据长时间没有更新,一段时间后,请求便会超时,client 收到超时信息后,再当即发送一个新的请求给 server。网络
如图所示,在长轮询机制下,client 向 server 发送了请求后,server会等数据更新完才会将数据返回,而不是像(短)轮询同样无论数据有没有更新而后当即返回。框架
这种方式也有弊端。当 server 向 client 发送数据后,必须等待下一次请求才能将新的数据发送出去,这样 client 接收到新数据的间隔最短期即是 2 * RTT(往返时间),这样便没法应对 server 端数据更新频率较快的状况。socket
流技术基于 Iframe。Iframe 是 HTML 标记,这个标记的 src 属性会保持对指定 server 的长链接请求,server 就能够不断地向 client 返回数据。
能够看出,流技术与长轮询的区别是长轮询本质上仍是一种轮询方式,只不过链接的时间有所增长,想要向 server 获取新的数据,client 只能一遍遍的发送请求;而流技术是一直保持链接,不须要 client 请求,当数据发生改变时,server 自动的将数据发送给 client。
如图所示,client 与 server 创建链接以后,便不会断开。当数据发生变化,server 便将数据发送给 client。
但这种方式有一个明显的不足之处,网页会一直显示未加载完成的状态,虽然我没有强迫症,但这点仍是难以忍受。
写到如今,你们会发现,前人推出那么多的解决方案,想要解决的惟一的问题即是怎么让 server 将最新的数据以最快的速度发送给 client。但 HTTP 是个懒惰的协议,server 只有收到请求才会作出回应,不然什么事都不干。所以,为了完全解决这个 server 主动向 client 发送数据的问题,W3C 在 HTML5 中提供了一种 client 与 server 间进行全双工通信的网络技术 WebSocket。WebSocket 是一个全新的、独立的协议,基于 TCP 协议,与 HTTP 协议兼容却不会融入 HTTP 协议,仅仅做为 HTML5 的一部分。
那 WebSocket 与 HTTP 什么关系呢?简单来讲,WebSocket 是一种协议,是一种与 HTTP 同等的网络协议,二者都是应用层协议,都基于 TCP 协议。可是 WebSocket 是一种双向通讯协议,在创建链接以后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在创建链接时须要借助 HTTP 协议,链接创建好了以后 client 与 server 之间的双向通讯就与 HTTP 无关了。
相比于传统 HTTP 的每次“请求-应答”都要 client 与 server 创建链接的模式,WebSocket 是一种长链接的模式。具体什么意思呢?就是一旦 WebSocket 链接创建后,除非 client 或者 server 中有一端主动断开链接,不然每次数据传输以前都不须要 HTTP 那样请求数据。从上面的图能够看出,client 第一次须要与 server 创建链接,当 server 确认链接以后,二者便一直处于链接状态。直到一方断开链接,WebSocket 链接才断开。
下面咱们从报文层面谈一下 WebSocket 与 HTTP 的差别。
首先,client 发起 WebSocket 链接,报文相似于 HTTP,但主要有几点不同的地方:
"Upgrade: websocket": 代表这是一个 WebSocket 类型请求,意在告诉 server 须要将通讯协议切换到 WebSocket
"Sec-WebSocket-Key: *": 是 client 发送的一个 base64 编码的密文,要求 server 必须返回一个对应加密的 "Sec-WebSocket-Accept" 应答,不然 client 会抛出 "Error during WebSocket handshake" 错误,并关闭链接
server 收到报文后,若是支持 WebSocket 协议,那么就会将本身的通讯协议切换到 WebSocket,返回如下信息:
"HTTP/1.1 101 WebSocket Protocol Handshake":返回的状态码为 101,表示赞成 client 的协议转换请求
"Upgrade: websocket"
"Connection: Upgrade"
"Sec-WebSocket-Accept: *"
...
以上都是利用 HTTP 协议完成的。这样,通过“请求-相应”的过程, server 与 client 的 WebSocket 链接握手成功,后续即可以进行 TCP 通信了,也就没有 HTTP 什么事了。能够查阅WebSocket 协议栈了解 WebSocket 的 client 与 server 更详细的交互数据格式。
网络应用中,两个应用程序同时须要向对方发送消息的能力(即全双工通讯),所利用到的技术就是 socket,其可以提供端对端的通讯。对于程序员而言,其须要在 A 端建立一个 socket 实例,并为这个实例提供其所要链接的 B 端的 IP 地址和端口号,而在 B 端建立另外一个 socket 实例,而且绑定本地端口号来进行监听。当 A 和 B 创建链接后,双方就创建了一个端对端的 TCP 链接,从而能够进行双向通讯。
WebSocekt 是 HTML5 规范中的一部分,其借鉴了 socket 的思想,为 client 和 server 之间提供了相似的双向通讯机制。同时,WebSocket 又是一种新的应用层协议,包含一套标准的 API;而 socket 并非一个协议,而是一组接口,其主要方便你们直接使用更底层的协议(好比 TCP 或 UDP)
Socket.IO 是一个封装了 Websocket、基于 Node 的 JavaScript 框架,包含 client 的 JavaScript 和 server 的 Node。其屏蔽了全部底层细节,让顶层调用很是简单。
另外,Socket.IO 还有一个很是重要的好处。其不只支持 WebSocket,还支持许多种轮询机制以及其余实时通讯方式,并封装了通用的接口。这些方式包含 Adobe Flash Socket、Ajax 长轮询、Ajax multipart streaming 、持久 Iframe、JSONP 轮询等。换句话说,当 Socket.IO 检测到当前环境不支持 WebSocket 时,可以自动地选择最佳的方式来实现网络的实时通讯。
参考:
微信公众号: 【龙果】 --- 《WebSocket --web持久链接神器》