网络编程:WebSocket协议浅析

欢迎关注colinsusie的微信公众号,colinsusie就是之前的colin大神哦!继续向colinsusie学习网络协议!

前言

当前好多手游都要求支持全平台,即要支持IOS和Android,也要支持原生App和H5,这让游戏的研发门槛越来越高。服务器这一端相对好一点,但也要考虑不同平台的通讯协议差异。综合各个平台的差异,只有HTTP和WebSocket是全平台支持的。HTTP适合于短连接的游戏,WebSocket则常用在长连接,通信比较频繁的游戏,比如像一些RPG,回合制,对战类的等等。

这一篇就来讲讲WebSocket协议的内容。

握手阶段

WebSocket以一个HTTP的请求和响应来进行握手,客户端请求的文本大概是这样:

GET / HTTP/1.1	
Host: example.com:8000	
Upgrade: websocket	
Connection: Upgrade	
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==	
Sec-WebSocket-Version: 13
  • 请求方法必须是GET,协议必须是1.1以上,请求路径没有强制要求,这里是/

  • Upgrade 必须是websocket,Connection必须是Upgrade

  • Sec-WebSocket-Version 为WebSocket版本号,当然是13

  • Sec-WebSocket-Key 是客户端发来的一个Key,看下面响应描述。

服务器响应的文本为:

HTTP/1.1 101 Switching Protocols	
Upgrade: websocket	
Connection: Upgrade	
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  • 响应码必须是101,表示Switching Protocols

  • Upgrade和Connection与上面一样

  • Sec-WebSocket-Accept根据上面请求的Sec-WebSocket-Key算出来的,它的算法是:Sec-WebSocket-Key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,然后计算出这个字符串的SHA-1哈希值,最后用base64得到结果。

响应完之后,握手完成,接下来就可以交换数据帧。

数据帧格式

每一个数据帧都包含帧头+有效数据,帧头的格式如下(注意字节顺序都是网络字节序):

0                   1                   2                   3	
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1	
+-+-+-+-+-------+-+-------------+-------------------------------+	
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |	
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |	
|N|V|V|V|       |S|             |   (if payload len==126/127)   |	
| |1|2|3|       |K|             |                               |	
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +	
|     Extended payload length continued, if payload len == 127  |	
+ - - - - - - - - - - - - - - - +-------------------------------+	
|                               |Masking-key, if MASK set to 1  |	
+-------------------------------+-------------------------------+	
| Masking-key (continued)       |          Payload Data         |	
+-------------------------------- - - - - - - - - - - - - - - - +	
:                     Payload Data continued ...                :	
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +	
|                     Payload Data continued ...                |	
+---------------------------------------------------------------+

协议的大概内容是:

  • 第1位FIN表示该帧是否为连续帧(即需要多个帧才能组成完整有效数据),如果为1表示单独帧,如果为0表示连续帧。我觉得这个有点过度设计了,连续帧应该由应用层自己解决,并且一个帧可以表示的长度是很长的,完全没必要设计这个连接帧。

  • RSV1~RSV3 这3位未用,默认为0。

  • opcode 为操作码,占4位,这个会决定该帧的类型,后面描述。

  • MASK 为掩码标志,占1位,如果为1,有效数据需要和Masking-key进行异或才得到原始数据,后面描述。

  • Payload len,Extended payload length 用于描述有效数据的大小,这个长度是动态的,后面描述。

  • Masking-key和MASK位结合,如果MASK为1,这个才会存在,否则不存在。

  • 后面就是上层应用的有效数据。

MASK数据

如果MASK位为1,那么Masking-key这4个字节就存在,用于和Playload data进行解码,才能得到原始的数据,解码的伪代码如下:

var DECODED = "";	
for (var i = 0; i < PayloadData.length; i++) {	
    DECODED[i] = PayloadData[i] ^ MaskKey[i % 4];	
}

这其实就是一种异或加密,客户端发过来的数据规定必须要加密。服务器可以根据需要自己决定。

Payload Data的长度

帧头有一块内容用来表示有效数据的大小,这一块内容是动态长度的,它是这样计算有效数据大小的:

  • 先读7位(Payload len),如果其值小于126,那么有效数据的长度就是它的值。

  • 如果等于126,还要再读16位,这16位的值就是有效数据的长度。

  • 如果等于127,还要再读64位,这64位的值就是有效数据的长度。

操作码

操作码分为两种,一种是数据类型,一种是控制码,描述如下:

  • 0x1 表示内容是文本数据,并且总是以utf-8编码。

  • 0x2 表示内容是二进制数据。

  • 0x9 是一个控制帧,叫PING帧。

  • 0xA 是一个控制帧,叫PONG帧,服务器收PING帧到后必须回应一个PONG帧,这其实就是一种心跳机制,且PING和PONG可以带有效数据,数据长度必须小于等125,即可以用前面的7位表示。

  • 0x8 是一个控制帧,叫关闭帧,告诉对端我要关闭了,关闭帧可以带有效数据,其中前面2个字节是关闭码,后面跟着utf-8的判断原因文本。。

  • 0x0 是一个控制帧,叫连续帧,假设连续帧有3帧,下面3帧的信息可以描述opcode和FIN怎么组合的: Client:FIN=0,opcode=0x1,msg="and a"Client:FIN=0,opcode=0x0,msg="happy new"Client:FIN=1,opcode=0x0,msg="c" 最后收到的信息就是: anda happynewhappynew

断开挥手阶段

  • 开始断开前,一端需要发送一个关闭控制帧。

  • 另一端收到关闭帧后,需要发送一个关闭帧作为响应。

  • 两端都发送并收到关闭帧后,就可以正常断开连接。

这个断开挥手阶段一直不大明白,TCP已经有断开过程了,WebSocket为什么还要自己设计一套挥手的过程,如果两端主动关闭,那么两端的TCP都会处于TIME_WAIT状态,这样会有什么好处呢?查看过几个实现,一般都是发送关闭帧后自己立即断开连接,并没有遵循WebSocket的协议说明等对端返回关闭帧才关闭。这个有人理解的话,欢迎告知。

关于WebSocket更详细的协议说明,请查看RFC6455

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值