在 WebSocket API 中,浏览器和做事器只须要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。(维基百科)
WebSocket 实质上一种打算机网络运用层的协议,用来填补 http 协议在持久通信能力上的不敷。
WebSocket 协议在2008年出身,2011年景为国际标准。现在最新版本浏览器都已经支持了。

它的最大特点便是,做事器可以主动向客户端推送信息,客户端也可以主动向做事器发送信息,是真正的双向平等对话,属于做事器推送技能的一种。
WebSocket 的其他特点包括:
(1)建立在 TCP 协议之上,做事器真个实现比较随意马虎。(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采取 HTTP 协议,因此握手时不随意马虎屏蔽,能通过各种 HTTP 代理做事器。(3)数据格式比较轻量,性能开销小,通信高效。(4)可以发送文本,也可以发送二进制数据。(5)没有同源限定,客户端可以与任意做事器通信。(6)协议标识符是ws(如果加密,则为wss),做事器网址便是 URL。ws://example.com:80/some/path
为什么须要 WebSocket?
我们已经有了 HTTP 协议,为什么还须要另一个协议?它能带来什么好处?
由于 HTTP 协议有一个毛病:通信只能由客户端发起,不具备做事器推送能力。
举例来说,我们想理解查询本日的实时数据,只能是客户端向做事器发出要求,做事器返回查询结果。HTTP 协议做不到做事器主动向客户端推送信息。
这种单向要求的特点,注定了如果做事器有连续的状态变革,客户端要获知就非常麻烦。我们只能利用"轮询":每隔一段时候,就发出一个讯问,理解做事器有没有新的信息。最范例的场景便是谈天室。轮询的效率低,非常摧残浪费蹂躏资源(由于必须一直连接,或者 HTTP 连接始终打开)。
在 WebSocket 协议涌现以前,创建一个和做事端进双通道通信的 web 运用,须要依赖HTTP协议,进行一直的轮询,这会导致一些问题:
做事端被迫坚持来自每个客户真个大量不同的连接大量的轮询要求会造成高开销,比如会带上多余的header,造成了无用的数据传输。http 协议本身是没有持久通信能力的,但是我们在实际的运用中,是很须要这种能力的,以是,为理解决这些问题,WebSocket 协议由此而生,于2011年被IETF定为标准RFC6455,并被RFC7936所补充规范。并且在 HTML5 标准中增加了有关 WebSocket 协议的干系 api ,以是只要实现了 HTML5 标准的客户端,就可以与支持 WebSocket 协议的做事器进行全双工的持久通信了。
WebSocket 与 HTTP 的差异WebSocket 与 HTTP 的关系图:
相同点: 都是一样基于TCP的,都是可靠性传输协议。都是运用层协议。联系: WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不须要HTTP协议的。
下面一张图解释了 HTTP 与 WebSocket 的紧张差异:
不同点:
1、 WebSocket 是双向通信协议,仿照 Socket 协议,可以双向发送或接管信息,而 HTTP 是单向的;2、 WebSocket 是须要浏览器和做事器握手进行建立连接的,而 http 是浏览器发起向做事器的连接。3、 虽然 HTTP/2 也具备做事器推送功能,但 HTTP/2 只能推送静态资源,无法推送指定的信息。三、WebSocket协议的事理与http协议一样, WebSocket 协议也须要通过已建立的TCP连接来传输数据。详细实现上是通过http协议建立通道,然后在此根本上用真正 WebSocket 协议进行通信,以是WebSocket协议和http协议是有一定的交叉关系的。首先, WebSocket 是一个持久化的协议,相对付 HTTP 这种非持久的协议来说。大略的举个例子吧,用目前运用比较广泛的 PHP 生命周期来阐明。
HTTP 的生命周期通过 Request 来界定,也便是一个 Request 一个 Response ,那么在 HTTP1.0 中,这次 HTTP 要求就结束了。
在 HTTP1.1 中进行了改进,使得有一个 keep-alive,也便是说,在一个 HTTP 连接中,可以发送多个 Request,吸收多个 Response。但是请记住 Request = Response, 在 HTTP 中永久是这样,也便是说一个 Request 只能有一个 Response。而且这个 Response 也是被动的,不能主动发起。首先 WebSocket 是基于 HTTP 协议的,或者说借用了 HTTP 协议来完成一部分握手。
首先我们来看个范例的 WebSocket 握手
GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com
熟习 HTTP 的童鞋可能创造了,这段类似 HTTP 协议的握手要求中,多了这么几个东西。
Upgrade: websocketConnection: Upgrade
这个便是 WebSocket 的核心了,见告 Apache 、 Nginx 等做事器:把稳啦,我发起的要求要用 WebSocket 协议,快点帮我找到对应的助理处理~而不是那个老土的 HTTP 。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13
首先, Sec-WebSocket-Key 是一个 Base64 encode 的值,这个是浏览器随机天生的,见告做事器:泥煤,不要忽悠我,我要验证你是不是真的是 WebSocket 助理。然后, Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同 URL 下,不同的做事所须要的协议。大略理解:今晚我要做事A,别搞错啦~末了, Sec-WebSocket-Version 是见告做事器所利用的 WebSocket Draft (协议版本),在最初的时候,WebSocket 协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么 Firefox 和 Chrome 用的不是一个版本之类的,当初 WebSocket 协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都利用同一个版本:做事员,我要的是13岁的噢→_→ 然后做事器会返回下列东西,表示已经接管到要求, 成功建立 WebSocket 啦!
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat
这里开始便是 HTTP 末了卖力的区域了,见告客户,我已经成功切换协议啦~
Upgrade: websocketConnection: Upgrade
依然是固定的,见告客户端即将升级的是 WebSocket 协议,而不是 mozillasocket ,lurnarsocket 或者 shitsocket。
然后, Sec-WebSocket-Accept 这个则是经由做事器确认,并且加密过后的 Sec-WebSocket-Key。做事器:好啦好啦,知道啦,给你看我的 ID CARD 来证明行了吧。后面的, Sec-WebSocket-Protocol 则是表示终极利用的协议。至此,HTTP 已经完成它所有事情了,接下来便是完备按照 WebSocket 协议进行了。总结, WebSocket 连接的过程是:
首先,客户端发起http要求,经由3次握手后,建立起TCP连接;http 要求里存放 WebSocket 支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等;然后,做事器收到客户真个握手要求后,同样采取HTTP协议回馈数据;末了,客户端收到连接成功的后,开始借助于TCP传输信道进行全双工通信。四、Websocket的优缺陷优点:
WebSocket协议一旦建议后,相互沟通所花费的要求头是很小的做事器可以向客户端推送了缺陷:
少部分浏览器不支持,浏览器支持的程度与办法有差异(IE10)五、WebSocket运用处景即时谈天通信多玩家游戏在线协同编辑/编辑实时数据流的拉取与推送体育/游戏实况实时舆图位置即时Web运用程序:即时Web运用程序利用一个Web套接字在客户端显示数据,这些数据由后端做事器连续发送。在WebSocket中,数据被连续推送/传输到已经打开的同一连接中,这便是为什么WebSocket更快并提高了运用程序性能的缘故原由。例如在交易网站或比特币交易中,这是最不稳定的事情,它用于显示价格颠簸,数据被后端做事器利用Web套接字通道连续推送到客户端。游戏运用程序:在游戏运用程序中,你可能会把稳到,做事器会持续吸收数据,而不会刷新用户界面。屏幕上的用户界面会自动刷新,而且不须要建立新的连接,因此在WebSocket游戏运用程序中非常有帮助。谈天运用程序:谈天运用程序仅利用WebSocket建立一次连接,便能在订阅户之间交流,发布和广播。它重复利用相同的WebSocket连接,用于发送和吸收以及一对一的传输。六、websocket 断线重连心跳便是客户端定时的给做事端发送,证明客户端是在线的, 如果超过一定的韶光没有发送则便是离线了。
如何判断在线离线?当客户端第一次发送要求至做事端时会携带唯一标识、以及时间戳,做事端到db或者缓存去查询改要求的唯一标识,如果不存在就存入db或者缓存中, 第二次客户端定时再次发送要求依旧携带唯一标识、以及时间戳,做事端到db或者缓存去查询改要求的唯一标识,如果存在就把上次的韶光戳拿取出来,利用当前韶光戳减去上次的韶光, 得出的毫秒秒数判断是否大于指定的韶光,若小于的话便是在线,否则便是离线;
如何解决议确定线问题通过查阅资料理解到 nginx 代理的 websocket 转发,无连接会涌现超时断开问题。网上资料提到办理方案两种,一种是修正nginx配置信息,第二种是 websocket 发送心跳包。下面就来总结一下本次项目实践中办理的 websocket 的断线 和 重连 这两个问题的办理方案。主动触发包括主动断开连接,客户端主动发送给后端
1 主动断开连接ws.close();
主动断开连接,根据须要利用,基本很少用到。
2 主动发送ws.send("hello world");
断线的可能缘故原由1:websocket超时没有自动断开连接,应对方法:这时候我们就须要知道做事端设置的超时时长是多少,在小于超时时间内发送心跳包,有2上钩划:一种是客户端主动发送上行心跳包,另一种方案是做事端主动发送下行心跳包。
下面紧张讲一下客户端也便是前端如何实现心跳包:
首先理解一下心跳包机制
跳包之以是叫心跳包是由于:它像心跳一样每隔固定时间发一次,以此来见告做事器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特殊规定的,不过一样平常都是很小的包,或者只包含包头的一个空包。
在 TCP 的机制里面,本身是存在有心跳包的机制的,也便是 TCP 的选项:SO_KEEPALIVE 。系统默认是设置的2小时的心跳频率。但是它检讨不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一样平常,如果只是用于保活还是可以的。
心跳包一样平常来说都是在逻辑层发送空的 echo 包来实现的。下一个定时器,在一定韶光间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,做事器如果在一定韶光内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
在长连接下,有可能很长一段韶光都没有数据往来。理论上说,这个连接是一贯保持连接的,但是实际情形中,如果中间节点涌现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定韶光之内没有数据交互的连接给断掉。在这个时候,就须要我们的心跳包了,用于坚持长连接,保活。
心跳检测步骤:
客户端每隔一个韶光间隔发生一个探测包给做事器客户端发包时启动一个超时定时器做事器端吸收到检测包,该当回应一个包如果客户机收到做事器的应答包,则解释做事器正常,删除超时定时器如果客户真个超时定时器超时,依然没有收到应答包,则解释做事器挂了// 前端办理方案:心跳检测var heartCheck = { timeout: 30000, //30秒发一次心跳 timeoutObj: null, serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.timeoutObj = setTimeout(function(){ //这里发送一个心跳,后端收到后,返回一个心跳, //onmessage拿到返回的心跳就解释连接正常 ws.send("ping"); console.log("ping!") self.serverTimeoutObj = setTimeout(function(){//如果超过一定韶光还没重置,解释后端主动断开了 ws.close(); //如果onclose会实行reconnect,我们实行ws.close()就行了.如果直接实行reconnect 会触发onclose导致重连两次 }, self.timeout); }, this.timeout); }}
断线的可能缘故原由2:websocket 非常包括做事端涌现中断,交互切屏等等客户端非常中断等等 当若做事端宕机了,客户端怎么做、做事端再次上线时怎么做?客户端则须要断开连接,通过 onclose 关闭连接,做事端再次上线时则须要打消之间存的数据,若不用除 则会造成只要要求到做事真个都会被视为离线。
针对这种非常的中断办理方案便是处理重连,下面我们给出的重连方案是利用js库处理:引入reconnecting-websocket.min.js,ws建立链接手法利用js库api方法:
var ws = new ReconnectingWebSocket(url);// 断线重连:reconnectSocket(){ if ('ws' in window) { ws = new ReconnectingWebSocket(url); } else if ('MozWebSocket' in window) { ws = new MozWebSocket(url); } else { ws = new SockJS(url); }}
断网监测支持利用js库:offline.min.js
onLineCheck(){ Offline.check(); console.log(Offline.state,'---Offline.state'); console.log(this.socketStatus,'---this.socketStatus'); if(!this.socketStatus){ console.log('网络连接已断开!
'); if(Offline.state === 'up' && websocket.reconnectAttempts > websocket.maxReconnectInterval){ window.location.reload(); } reconnectSocket(); }else{ console.log('网络连接成功!
'); websocket.send("heartBeat"); }}// 利用:在websocket断开链接时调用网络中断监测websocket.onclose => () { onLineCheck();};
以上方案,只是抛砖引玉,如果大家有更好的办理方案欢迎评论区分享互换。
七、总结WebSocket 是为了在 web 运用上进行双通道通信而产生的协议,比较于轮询HTTP要求的办法,WebSocket 有节省做事器资源,效率高档优点。WebSocket 中的掩码是为了防止早期版本中存在中间缓存污染攻击等问题而设置的,客户端向做事端发送数据须要掩码,做事端向客户端发送数据不须要掩码。WebSocket 中 Sec-WebSocket-Key 的天生算法是拼接手事端和客户端天生的字符串,进行SHA1哈希算法,再用base64编码。WebSocket 协议握手是依赖 HTTP 协议的,依赖于 HTTP 相应101进行协议升级转换。
参考阮一峰:WebSocket 教程看完让你彻底理解 WebSocket 事理