Go最全WebSocket协议解析_decoding websocket frame opcode=9(2),36岁老码农现身说法

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

设计原理

  • 元数据:与HTTP协议不同,websocket的元数据是由应用层自行传输的。
  • websocket是基于帧来传输而不是基于流的,每一帧要么承载字符数据,要么成长二进制数据。
  • 基于浏览器同源策略模型,可以使用Access-Control-Allow-Origin等头部。
  • 基于URI、子协议支持同主机同端口上的多个服务。

协议格式

学习协议必然要学习他的协议定义,WebSocket的最小单位是帧,由1个或多个帧组成一条消息。

  • 发送端:将消息切割成多个帧,并发送。
  • 接收端:接收消息帧,并将关联的帧重新组装成完整的消息。

数据帧格式

  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 ...                |
 +---------------------------------------------------------------+


  • FIN:1bit,如果是1,表示这是消息的最后一个分片,如果是0表示不是消息的分片
  • RSV1,RSV2,RSV3:各占1bit,一般情况全为0。当采用websocket扩展时,这三个标志位可以非0,且值含义由扩展进行定义。如果出现非零的值且没有采用websocket扩展连接出错。
  • Opcode:4bit。
    • 0:延续帧,表示本次分片,当前收到的数据帧为其中一个数据分片。
    • 1:文本真。
    • 2:二进制帧。
    • 3-7:为非控制帧保留。
    • 8:连接断开。
    • 9:心跳帧ping。
    • 10:心跳帧pong。
    • B-F:保留
  • Mask:1bit。表示是否对数据载荷进行掩码操作。从客户端向服务器发送数据时需要对数据进行掩码操作,当从服务端向客户端发送数据时,不需要对数据及逆行掩码操作。如果服务端接收到的数据没有进行过掩码操作,服务端就需要断开连接。如果mask为1,那么masking-key中会定义一个掩码键,并用这个掩码键来对数据进行反掩码。所有客户端发送到服务端的数据帧mask都是1。
  • Payload Length:数据的长度,单位是字节,为7位或7+16位或1+64位。
    • 0-126:数据长度为x字节。
    • 126:后续2个字节为16位无符号整数,为数据的长度.
    • 127:后续8个字节为64位无符号整数,为数据长度。

掩码

掩码算法

掩码键(Masking-key)是由客户端挑选出来的32位的随机数。掩码操作不会影响数据载荷的长度。掩码、反掩码操作都采用如下算法:
首先,假设:

  • original-octet-i:为原始数据的第i字节。
  • transformed-octet-i:为转换后的数据的第i字节。
  • j:为i mod 4的结果。
  • masking-key-octet-j:为mask key第j字节。

算法描述为: original-octet-i 与 masking-key-octet-j 异或后,得到 transformed-octet-i。
j = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j

掩码作用

![image.png](https://img-blog.csdnimg.cn/img_convert/8260c77e25b2eaeaf805520714e27810.png#clientId=u9ee83695-c277-4&from=paste&height=392&id=ua3df7cc7&margin=[object Object]&name=image.png&originHeight=784&originWidth=1135&originalType=binary&ratio=1&size=188314&status=done&style=none&taskId=u07f242c4-b8b5-47a2-9f5d-96f32d8b50e&width=567.5)

流程

URI格式

ws-URI:ws://host:[:port]path[?query]

  • 默认为80

wss-URI:wss://host:[:port]path[?query]

  • 默认为443

连接说明:

  • host和port:主机名与端口
  • shema:是否基于SSL
  • 访问资源:URI
  • 握手随机数:Sec-WebSocket-Key
  • 选择子协议:Sec-WebSocket-Protocol
  • 扩展协议:Sec-WebSocket-Extensions
  • CORS跨域:Origin

握手建立

客户端
GET /?encoding=text HTTP/1.1 
Host: websocket.taohui.tech 
Accept-Encoding: gzip, deflate 
Sec-WebSocket-Version: 13 
Origin: http://www.websocket.org 
Sec-WebSocket-Extensions: permessage-deflate 
Sec-WebSocket-Key: c3SkgVxVCDhVCp69PJFf3A== 
Connection: keep-alive, Upgrade 
Pragma: no-cache 
Cache-Control: no-cache 
Upgrade: websocket

服务端
HTTP/1.1 101 Web Socket Protocol Handshake 
Server: openresty/1.13.6.2 
Date: Mon, 10 Dec 2018 08:14:29 GMT 
Connection: upgrade 
Access-Control-Allow-Credentials: true 
Access-Control-Allow-Headers: content-type 
Access-Control-Allow-Headers: authorization 
Access-Control-Allow-Headers: x-websocket-extensions 
Access-Control-Allow-Headers: x-websocket-version
Access-Control-Allow-Headers: x-websocket-protocol 
Access-Control-Allow-Origin: http://www.websocket.org 
Sec-WebSocket-Accept: yA9O5xGLp8SbwCV//OepMPw7pEI= 
Upgrade: websocket

如何验证握手被服务器接受?

  • 请求中的 Sec-WebSocket-Key 随机数
    • 例如 Sec-WebSocket-Key: A1EEou7Nnq6+BBZoAZqWlg==
  • 响应中的 Sec-WebSocket-Accept 证明值
  1. 拼接值,服务端会将客户端的Sec-WebSocket-KeyGUID拼接,GUID在RFC4122中规定,例如A1EEou7Nnq6+BBZoAZqWlg==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
  2. 将拼接后的进行SHA1编码
  3. 将SHA1编码再进行Hex base64编码
  4. 然后将其放到Sec-WebSocket-Accept: cT8V7OIhhhL8rbFZgoGjU4DReQ8=

心跳帧

websocket使用ping、pong心跳帧来维持连接
ping帧:opcode=9可以含有数据
pong帧:opcode=A必须与ping帧数据相同

关闭帧

websocket定义了关闭帧,opcode=8,发送关闭帧后,不再发送任何数据,接受到关闭帧后,不再接受任何数据。

关闭帧的错误码
错误码含义
1000正常关闭
1001表示浏览器页面跳转或者服务器将要关机
1002发现协议错误
1003接收到不能处理的数据帧(例如某端不能处理二进制消息)
1004预留
1005预留(不能用在关闭帧里),期望但没有接收到错误码
1006预留(不能用在关闭帧里),期望给出非正常关闭的错误码
1007消息格式不符合 opcode(例如文本帧里消息没有用 UTF8 编码)
1008接收到的消息不遵守某些策略(比 1003、1009 更一般的错误)
1009消息超出能处理的最大长度
1010客户端明确需要使用扩展,但服务器没有给出扩展的协商信息
1011服务器遇到未知条件不能完成请求
1015预留(不能用在关闭帧里),表示 TLS 握手失败

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值