[WebSocket] websocket 概述

背景介绍:

随着互联网的发展,Web系统也有了长足的进步,但是各种实用的需求也应用而生,比如WEBIM(WEB及时通讯系统),及时报价系统,股票实时行情,火车票剩余量等等,服务端发生的数据变化及时的推送到客户端,如果客户端主动请求(每隔一定的时间)服务端(轮询),并不能保证数据的及时性。服务端主动推送到客户端,我们知道http协议是一种单向网络协议,在建立连接后,它只允许Browser/UA(UserAgent)向WebServer发送请求资源后,WebServer才能返回相应的数据,而WebServer不能主动推送数据到Browser/(UserAgent),当初这么设计http协议也是有原因的,假设WebServer能主动的推送数据给Browser/UA,那Browser/UA太容易受到攻击,一些广告商也会主动把一些广告信息在不经意间强行的传输给客户端,这不能不说是一个灾难,服务器不能向客户端主动推送数据,就会造成客户端抓到的数据不能保证实时性。如果客户端使用AJAX向服务端发起请求,服务端有数据或者超时的时候再返给客户端(长轮询),同样不能保证客户端接收的数据的及时性,并且响应时间为 2*RTT,用户体验差。用在大型商业应用中,客户端与服务端的连接太多,服务端需要维护大量的并发HTTP长连接,这中应用背景下,服务端需要考虑负载均衡和集群技术。
 
轮询、长轮询、长连接 技术的发展:
1. AJAX轮询(Polling):
 
场景再现:
 
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response)
 
原理图如下:
 
                            
这是一种通过Browser/UA定时的向Web服务器发送http的Get请求,服务器受到请求后,就把最新的数据发回给客户端(Browser/UA),Browser/UA得到数据后就将其显示出来,然后再定期重复这一过程,虽然这可以满足需求,但也存在一些问题,例如某段时间服务器端的数据没有更新,客户端仍然不断的向服务器发送请求,这样既费网络带宽,又浪费服务器CPU利用率,如果说把客户端发送到服务端请求的周期放大一些,又会造成获取的数据不是及时的。
 
2. 长轮询(Long Polling)-----Comet
场景再现:
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
原理图如下:
 
                            
长轮询是对轮询的一种改进,当客户端Browser/UA发送Get请求到服务器时,服务器做两件事,首先判断是否有新数据更新,如果有,就会将新数据返回给客户端,如果没有数据更新,服务端会hold住这个请求(采取的阻塞模式--一直打电话,没收到就不挂电话),直到有新数据或者该请求超时时,才会有结果返回给客户端。这种方式虽然在某种程度上减小了网络宽带和CPU利用率等,但仍存在缺陷,例如:加入服务器端数据更新的太快,在等待客户端发来获取数据的请求前,该数据已经不止被更新了一次,这样的话仍存在数据及时性的问题,并且客户端接收到的数据最快为请求时间的2倍,也就是2*RTT(返回时间),另外在网络阻塞的情况下,更不能被用户所接收。另外http数据包的头部的数据量往往很大(通常400字节),而真正被服务器需要的数据却很少(有时只有10个字节左右),这样在网络上周期性的传说难免会造成网络带宽的浪费。
 
通过以上分析,要是在Browser能有一种新的网络协议,能支持客户端和服务端的双向通信,而且协议头部不那么庞大就好了,WebSocket就肩负起这个使命登上了舞台。
 
3. Stream(流)-----Comet
流技术方案通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服 务器端的连接不过期。通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改 进用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。
 
4. WebSocket
场景再现:
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request)
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:哈哈哈哈哈啊哈哈哈哈
 
 
WebSocket 协议是一种持久化的双向通信协议,持久化体现在websocket有一个keep-alive,同http一样建立在TCP协议之上,通过TCP来传输数据,但是和http最大的不同在于,由于他是一种建立在Web基础上的一种简单模拟Socket的协议,所以在客户端Browser/UA与服务端WebSercer建立连接后,服务端能够主动向客户端推送数据。而且通信的过程中,比起以前使用的http传输数据,websocket传输的额外信息很少,据百度所只有2k左右。
 
对HTTP与WebSocket之间关系的理解如下图:(有交集,但是并不是全部)
                
 
WebSocket同http一样都基于TCP协议,客户端与服务端之间在传输数据之前也就进行三次握手:
 
⑴ 当Web应用程序调用new WebSocket(url)接口时,Browser就开始了与地址url的WeSocket建立握手连接的过程。
⑵ 在TCP建立连接成功后,Browser/UA通过http协议传送WebSocket支持的版本号,协议的字版本号,原始地址,主机地址等等一系列字段给服务器端
⑶ 服务器端受到浏览器发送来的握手请求后,如果数据包格式正确,客户端和服务端版本号匹配等等,就接收本次握手,并给出相应的数据回复,同样回复的数据包也采用http协议传输。
⑷ 浏览器收到服务器回复的数据包后,再做一些教研没问题的话,就表示本次连接成功,触发onopen消息,此时Web开发者就可以再次通过send接口向服务器发送数据,否则握手失败,Web应用程序会收到onerror消息,并且能知道连接失败的原因。
 
三次握手图如下:
 
                            
 
注意:
objWs为新创建的WebSocket对象,send()方法中的dataInfo参数为字符类型,即只能使用文本数据或者将JSON对象转换成文本内容的数据格式。
 
WebSocket 的四个状态属性值:
 
                
 
客户端发送请求:
 
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 127.0.0.1:8080
Origin: http://test.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: OtZtd55qBhJF2XLNDRgUMg==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36
 
理解:
Upgrade: websocket
Connection: Upgrade
这个就是Websocket的核心了,告诉Apache、Nginx等服务器:注意啦,窝发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-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岁的噢→_→
 
 
服务端做出响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: xsOSgr30aKL2GNZKNHKmeT1qYjA=
在请求中”Sec-WebSocket-key“是随机的,服务器端会用这些数据构造出一个SHA-1的信息摘要。把”Sec-WebSocket-Key“加上一个魔幻字符串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11“。使用SHA-1加密,之后进行BASE-64编码,将结果作为”Sec-WebScoket-Accept“头的值,返回给客户端。
理解:
依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket。
然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。
后面的,Sec-WebSocket-Protocol 则是表示最终使用的协议。

 
-----------------------------------------------资料查找-----------------------------------------------
Asp.Net实现简单的Comet(例子)
Asp.Net和JQuery的Comet实现(例子)
WebSocket(原理,C#服务端例子)
 
WebSocket协议详解、以及传大数据时分包思想
浏览器中如何接收图片
 
WebSocket高并发服务器端处理策略
 
WebSocket实现(较详细)★
-------------------------------------------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
posted @ 2019-04-30 16:03  NCat  阅读(285)  评论(0)    收藏  举报