当前位置: 首页 > news >正文

websocket 内的操作码fin和opcode

websocket传输的头两个字节非常关键,提供了每一帧的基本信息,RFT6455中给出了帧头的格式说明:

      0                   1                   2                   30 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位和opcode位,用c++的struct bit field配合union可以方便的对数据实现存取,这儿给出一个例子:

#ifndef TAGWEBSCOKETFRAMEOPCODE_H
#define TAGWEBSCOKETFRAMEOPCODE_H
//Begin section for file tagWebScoketFrameOpCode.h
//TODO: Add definitions that you want preserved
//End section for file tagWebScoketFrameOpCode.h
#include "../../Common.h"namespace boson
{//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"union tagWebScoketFrameOpCode{//Begin section for boson::tagWebScoketFrameOpCode//TODO: Add attributes that you want preserved//End section for boson::tagWebScoketFrameOpCodepublic://@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"struct tagWebScoketFrameOpCodeBits{//Begin section for boson::tagWebScoketFrameOpCode::tagWebScoketFrameOpCodeBits//TODO: Add attributes that you want preserved//End section for boson::tagWebScoketFrameOpCode::tagWebScoketFrameOpCodeBitspublic:#if BYTE_ORDER == LITTLE_ENDIAN//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 code : 4;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 rsv3 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 rsv2 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 rsv1 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 fin0 : 1;#elif BYTE_ORDER == BIG_ENDIAN//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 fin0 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 rsv1 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 rsv2 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 rsv3 : 1;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 code : 4;#endif };  //end struct tagWebScoketFrameOpCodeBitspublic://@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"U08 data;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"tagWebScoketFrameOpCodeBits bits;//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"tagWebScoketFrameOpCode(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"tagWebScoketFrameOpCode(const tagWebScoketFrameOpCode & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"~tagWebScoketFrameOpCode(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"tagWebScoketFrameOpCode & operator=(const tagWebScoketFrameOpCode & value ); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"void Clear(); };  //end union tagWebScoketFrameOpCode} //end namespace boson#endif

 在定义结构体的时候休要注意字节序的大小端区别,这篇文章要讲的就是就是这个字节数据所代表的含义。

这个字节由几部分构成:fin, rsv1, rsv2, rsv3, opcode,其中对 fin 的解释如下:

FIN: 1 bit

Indicates that this is the final fragment in a message. The first fragment MAY also be the final fragment.

fin 的含义很简单:这一段数据是否是最后一部分数据。因为websocket允许将一段长数据拆分成多个帧来发送,避免如果一帧内发送数据太长,对控制帧造成的阻塞。因此在实现的时候,必须考虑拆分较长的数据,每一帧发送不超过限度的长度,比如64K字节。

rsv1 - 3 不用考虑,被保留的位。

opcode 的解释如下:

Opcode: 4 bits

Defines the interpretation of the "Payload data". If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_. The following values are defined.

* %x0 denotes a continuation frame

* %x1 denotes a text frame

* %x2 denotes a binary frame

* %x3-7 are reserved for further non-control frames

* %x8 denotes a connection close

* %x9 denotes a ping

* %xA denotes a pong

* %xB-F are reserved for further control frames

opcode 是帧的用途定义,这儿简单做一个解释:

0 表示连续帧,1 表示 payload 是文本,2 表示 payload 是二进制流,

3 - 7 保留,

8 连接关闭,9 心跳 ping,A 心跳 pong,

B - F 保留。

其中,0,1,2是正常传输数据用的代码,8,9,A是标准的控制帧。

在 webscoket 中,控制帧有一个限定:控制帧不允许分段(5.4. Fragmentation),意思就是,控制帧只允许作为一个完整的帧一次性发送。不能像数据帧那样分段发送,因此在微软实现的webscoket 类中,如关闭帧只允许带最长125字节的数据(还包括两字节的状态码)。

做出这样的限制的目的是,控制帧允许在分段的数据之间发送。因此,为什么将0,1,2和8,9,A分列开,也是处于这个原因。

在分段传递数据时, 会先收到一个Text / Binary opcode, 它的Fin位是0 (More Fragment), 后续的数据会以Continuation Frame的形式发送, 直到最后一片Fin位是1 (Last Fragment) 的Continuation Frame结束, 中间不会穿插其它的数据帧(控制帧除外, 例如Close, Ping, Pong)。

所以我们在处理webscoket帧的时候,如果Fin位为0,则不处理,将帧放入一个缓存,发现 Fin 位为1 的时候就可以处理帧了,根据帧的opcode来判断,如果是控制帧就直接处理,如果连续帧,就将之前缓存的帧拼接成一个完整的payload即可。

相关文章:

  • 数据结构万字总结(超级详细)第二章——线性表
  • JVM虚拟机-实战篇
  • AI+云平台|全闪云底座迎战
  • 自媒体用ChatGPT批量洗稿软件V5.9环境配置/软件设置教程【汇总】
  • UE5C++学习(四)--- SaveGame类存储和加载数据
  • Sql Server小技能:row_number()函数
  • 【Vue】Vue集成Element-UI框架
  • 深圳区块链交易所app系统开发,撮合交易系统开发
  • 服务器总是宕机问题记录
  • 【WPF应用7】 基本控件-Grid 布局的详解与示例
  • 如何在Linux系统使用Docker本地部署Halo网站并实现无公网IP远程访问
  • Python读取csv文件入Oracle数据库
  • vivado 使用远程主机和计算群集
  • 接招吧! selenium环境+元素定位大法
  • TCP重传机制详解——03DSACK
  • Angular 4.x 动态创建组件
  • angular2 简述
  • CentOS从零开始部署Nodejs项目
  • Javascript编码规范
  • Linux gpio口使用方法
  • Material Design
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 反思总结然后整装待发
  • 看域名解析域名安全对SEO的影响
  • 前端js -- this指向总结。
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 深入浏览器事件循环的本质
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 鱼骨图 - 如何绘制?
  • 关于Android全面屏虚拟导航栏的适配总结
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • (16)Reactor的测试——响应式Spring的道法术器
  • (附源码)springboot教学评价 毕业设计 641310
  • (十)T检验-第一部分
  • (顺序)容器的好伴侣 --- 容器适配器
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)http-server应用
  • (转)linux 命令大全
  • ******IT公司面试题汇总+优秀技术博客汇总
  • .bat批处理出现中文乱码的情况
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET简谈设计模式之(单件模式)
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • /proc/vmstat 详解
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [APIO2015]巴厘岛的雕塑
  • [Avalon] Avalon中的Conditional Formatting.
  • [BT]BUUCTF刷题第4天(3.22)
  • [BZOJ4016][FJOI2014]最短路径树问题
  • [CareerCup] 2.1 Remove Duplicates from Unsorted List 移除无序链表中的重复项
  • [CC2642r1] ble5 stacks 蓝牙协议栈 介绍和理解