网络编程—构建WebSocket服务
2018-07-19 本文已影响33人
励志摆脱懒癌的少女酱
websocket
-
简介
http交互图
websocket是在tcp上定义的独立的协议,相比http,其更接近于传输层协议,没有同源限制,实现浏览器和服务器全双工通信;其协议主要分为:握手和数据传输 — http一定是请求和响应一一对应,而websocket连接建立后,后续数据以帧序列的形式传输;
websocket交互图 -
Web实时性
(1)轮询机制- 定时轮询:客户端以一定的时间间隔像服务端发出请求,以频繁请求的方式保持客户端和服务器端的同步;
- 缺点:当客户端以固定频率向服务端发起请求时,服务端的数据可能没有更新,这样造成很多无谓的网络传输,非常低效;
- 长轮询(comet): 当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或时间过期;
* 目的:降低无效的网络传输,但当服务端的数据变更非常频繁的话,该机制和定时轮询在性能上差不多;
(2)流技术 - 流:在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求,服务端收到这个请求后做出回应并不断更新连接状态以保证客户端和服务器端的连接不过期;
- 缺点:需要针对不同的浏览器设计不同的方案来改进用户体验;
注:以上两种方案在每次客户端和服务端交互时都是一次HTTP请求和应答的过程: - 每一次HTTP请求和应答都带有完整的HTTP头信息,增加了每次传输的数据量;
-
需要构造两个HTTP连接来模拟客户端和服务端之间的双向通信;
长轮询
(3)WebSocket:使用js调用浏览器的API发出一个WebSocket请求至服务器,经过一次握手,和服务器建立TCP通信;
- 优点:
- 只建立一个TCP连接,就可以主动推送数据到客户端;
-
更轻量级的协议头,减少数据传送量;
Websocket
- 缺点:需要针对不同的浏览器设计不同的方案来改进用户体验;
- 定时轮询:客户端以一定的时间间隔像服务端发出请求,以频繁请求的方式保持客户端和服务器端的同步;
websocket协议组成
-
websocket握手:由http完成;
(1)客户端建立连接时,通过http发起请求报文:
- 请求服务器升级协议为websocket:
- Upgrade:websocket
- Connection:Upgrade
- 安全校验
- Sec-WebSocket-Key:随机生成的Base64编码的字符串;
- 直到子协议及版本号
- Sec-WebSocket-Protocol: chat, superchat
- Sec-WebSocket-Version: 13
客户端发起的请求
(2)服务器:告诉客户端正在更新应用层协议为websocket协议,并在当前的套接字连接上应用新协议;
报文头:HTTP/1.1 101 Switching Protocols;— 101状态码表示切换协议成功;
Upgrade:Websocket;
Connection:Upgrade;
Sec-WebSocket-Accept : Sec-WebSocket-Key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' -> SHA1编码得到多组两位16进制数构成的加密串 -> 进行base64编码得到最终的key;
客户端将校验Sec-WebSocket-Accept的值,若成功,将开始接下来的数据传输。
服务端的响应
注:Sec-WebSocket-Key和Sec-WebSocket-Accept作为重要的握手认证信息;
2.** 数据传输**
(1)方法
- send():发送数据;
- onmessage():接受数据时触发;
为了安全,客户端需要对发送的数据帧进行掩码处理,服务器一旦收到无掩码帧(中间拦截破坏),连接将关闭;而服务器发送给客户端的数据帧则无须做掩码处理,若客户端收到了带掩码的数据帧,连接也关闭。
(2)数据帧的定义:一个字节8位;
- fin(1位):标识该数据帧是否是最后一帧;(1:最后一帧;0:不是最后一帧)
- rsv1、rsv2、rsv3(各1位长):3个标识用于扩展,当有已协商的扩展时,这些值为1,否则为0;
- opcode(4位):用于解释当前数据帧 ;
- 0表示附加数据帧;
- 1表示文本数据帧;
- 2表示二进制数据帧;
- 8表示发送一个连接关闭的数据帧;
- 9表示ping数据帧;
- 10表示pong数据帧(9和10是成对的);
- masked(1位):表示是否进行掩码处理;
- 客户端发送给服务器时是1;
- 服务器发送给客户端是0;
- payload length(7bit、7bit+2byte、7bit+8byte):标识数据的长度;
- 值是0~125之间,就是数据的真实长度;
- 值是126(1111110),后面的16位是数据的真实长度;
- 值是127(1111111),后面的64位是数据的真实长度;
- masking key(32位):当masked为1时存在,用于解密数据;
- payload data(8n位):目标数据;
eg:客户端发送hello world!
数据较短,不需要分割为多个数据帧,以文本方式发送,payload length为1100000=96(12字节*8位/字节),所以报文为:
fin(1)+res(000)+opcode(0001)+maked(1)+payload length(1100000)+masking key(32位)+payload data(hello world!加密后的二进制)
服务端在data事件(在tcp层封装的)中接收这些编码数据,然后解析为相应的数据帧,再以数据帧的格式,通过掩码将真正的数据解密出来,然后触发onmessage()执行;
eg:服务器端响应yakexi的报文:
fin(1)+res(000)+opcode(0001)+masked(0)+payload length(110000)+payload data(yakexi的二进制)