1. websocket协议
WebSocket协议提供一个供TCP连接进行双向通讯的机制,基于TCP传输协议,并复用HTTP的握手通道。
2. 长连接,轮询,长轮询,websocket的前世今生
我们可能经常会听到长连接,轮询,长轮询,websocket这几个概念,并且可能对他们的区别有些模糊
2.1 websocket与http的关系
他和http的协议就如同下面的关系,有共用的部分,但不是一个东西。Websocket其实是一个新协议,跟HTTP协议不同,为了兼容现有浏览器的握手规范,借用了HTTP的协议来完成一部分握手,所以他们在握手阶段是基本一样的。
2.2 长连接
在我们的认识下,http协议中,Request = Response,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。
每一个请求开始后都会经历握手的过程,握手结束后开始传输数据,显然这样的效率不高,所有聪明的开发者们想到了,可不可以在一次握手结束后,发送多个请求,并接收多个请求,keep-alive应运而生。HTTP有1.1和1.0之说,http1.1一个比较重要的方面就是增加了keep-alive,HTTP1.1的连接默认使用持续连接。
2.3 轮询
轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:.有没有新信息(Request)
服务端:没有.(Response)
客户端:..有没有新信息(Request)
服务端:没有..(Response)
客户端:...有没有新信息(Request)
服务端:有消息,告诉你,今天要下雨...(Response)
客户端:...有没有新消息(Request)
服务端:没有..(Response)
。。。。。。
---- loop
很明显这样的方式,轮询就会造成对网络和通信双方的资源的浪费,且非实时
2.4 长轮询
长轮询其实原理跟轮询差不多,都是采用轮询的方式,不过采取的是阻塞模型,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景再现
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
。。。。
----loop
相比于轮询,这种方式网络带宽占用少了,但是本质上都体现了服务器的被动型,只有请求过来,才能回答,不能主动与客户端沟通。
2.5 websocket
相对于http协议,websocket协议在握手阶段结束,建立起连接后,双方通讯会一直保持,并且客户端和服务端任何一方都可以主动向对方发送新消息,并且另一端通过监听onXXX事件可以收到这个信息。
3. websocket的详细介绍
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。WebSocket 允许服务器端与客户端进行全双工(full-duplex)的通信。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信,完全可以取代 Ajax。
(6)协议标识符是ws(如果加密,则为wss,对应 HTTPS 协议),服务器网址就是 URL。
WS协议有两部分组成:握手和数据传输。
3.1 websocket握手阶段
这就是我们所了解的TCP三次握手,重温下这个经典的瞬间。。。
下面是我截取的一个websocket请求
通过上图可以看到和http的请求响应很像,
请求头中,这里需要注意几个域,有一个 HTTP 头是Upgrade。HTTP1.1 协议规定,Upgrade表示将通信协议从HTTP/1.1转向该字段指定的协议。Connection字段表示浏览器通知服务器,如果可以的话,就升级到 WebSocket 协议。Origin字段用于提供请求发出的域名,供服务器验证是否许可的范围内(服务器也可以不验证)。Sec-WebSocket-Key则是用于握手协议的密钥,是 Base64 编码的16字节随机字符串。
响应头中,服务器同样用Connection字段通知浏览器,需要改变协议。Sec-WebSocket-Accept字段是服务器在浏览器提供的Sec-WebSocket-Key字符串后面,添加“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”字符串,然后再取 SHA-1 的哈希值。浏览器将对这个值进行验证,以证明确实是目标服务器回应了 WebSocket 请求。
3.2 数据传输
看一下客户端的简单实例
var ws = new WebSocket('wss://echo.websocket.org');
ws.onopen = function(evt) {
console.log('Connection open ...');
ws.send('Hello WebSockets!');
};
ws.onmessage = function(evt) {
console.log('Received Message: ' + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log('Connection closed.');
};
代码比较简单,也容易理解,就是几个回调函数。同样服务端也要实现监听事件,这样双方就可以通讯了。需要注意的是,websocket不仅可以发送text类型数据,还可以发送二进制数据,如果有需要,on message 的时候可以进行下判断。
参考资料
https://www.zhihu.com/question/20215561
http://javascript.ruanyifeng.com/htmlapi/websocket.html#toc0