前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络编程:WebSocket协议浅析

网络编程:WebSocket协议浅析

作者头像
张晓衡
发布2019-09-11 18:42:02
6760
发布2019-09-11 18:42:02
举报
文章被收录于专栏:Creator星球游戏开发社区

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

前言

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

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

握手阶段

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

代码语言:javascript
复制
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,看下面响应描述。

服务器响应的文本为:

代码语言:javascript
复制
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得到结果。

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

数据帧格式

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

代码语言:javascript
复制
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进行解码,才能得到原始的数据,解码的伪代码如下:

代码语言:javascript
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Creator星球游戏开发社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 握手阶段
  • 数据帧格式
    • MASK数据
      • Payload Data的长度
        • 操作码
        • 断开挥手阶段
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档