揭秘通信协议设计的奥妙,作为面试官我都看蒙了

2023-11-09 08:20

本文主要是介绍揭秘通信协议设计的奥妙,作为面试官我都看蒙了,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本节将重点探讨网络编程中一种非常通用的协议设计方法论:协议头 + 消息体。

所谓的通信协议就是通信双方共同遵循的一种“约定”,用于通信发送方将内容按照“通信协议”所规定的格式组装成**“二进制流”**,通信接收方按照“通信协议”所规定的格式正确的从二进制流中解码出一个个原始请求。

那通信协议如何设计呢?

1、通用的协议设计方法论

在网络编程中,流行着一种经典的协议设计方法论:协议头 + 消息体。

其设计的关键点如下:

协议头的长度是固定的,通常为识别一个业务的最小长度

协议头中会包含一个长度字段,用来标识一个完整包的长度,用来表示长度字段的字节位数直接决定了一个包的最大长度,长度字段通常被设计为4个字节。

消息体中存储业务数据,例如如果是一个Dubbo协议,那消息体中可能会包含请求参数、调用的服务名等,而且字符串类的存储通常会采取字段长度、字段内容的组织方式。

为了有一个更直观的展示,我以一个简单的RPC通信场景为例,实现类似Dubbo服务的远程服务调用,其通信协议可以简单设置成下图所示:

基于 Header + Boby 的通信协议设计模式后,通信接收方就能很好的从二进制流中非常容易地解码出一条一条原始的请求数据包,解码的基本套路如下(在面试中面试官非常喜欢问的“粘包”问题的破解之道)

首先判断累积缓存区中是否存在一个完整的Head头部,例如上述示例中,一个包的Header的长度为6个字节,那首先判断累积缓存中可读字节数是否大于等于6,如果不足6个字节,跳过本次处理,等待更多数据到达累积缓存区

尝试将头部6个字节读取,并且提取长度字段中存储的数值,即包长度,然后判断累积缓存区中可读字节数大于等于整个包的长度,如果累积缓存区不包含一个完整的数据包,则跳过本次处理,等待更多数据到达累积缓存区。

如果包含一个完整的包,则按照通信协议的格式按序读取相关的内容。

正是因为这种设计理念非常通用,Netty 对上述协议设计进行了统一封装:

LengthFieldBasedFrameDecoder 闪亮登场了,接下来我们来看看Netty是如何进行封装的,揭晓更多的实现细节,让大家做到理论与实践相结合。

2、LengthFieldBasedFrameDecoder 详解

2.1 概述

接下来对其核心属性进行一个详细的解读:

ByteOrder byteOrder

字节序列,Netty默认使用大端序列(主要是针对int、long等数值类型),所谓的大端序列,通常可以这样理解,接收端收到的字节流的顺序是从数值类型的高字节。

int maxFrameLength

一条消息最大的长度。

int lengthFieldOffset

代表长度字段的开始偏移量。

int lengthFieldLength

代表长度字段占用的字节长度。

int lengthFieldEndOffset

代表长度字段的结束偏移量,等于lengthFieldOffset + lengthFieldLength。

int lengthAdjustment

长度适配适配值。该值表示协议中长度字段与消息体字段直接的距离。

int initialBytesToStrip

跳过一个包中前面多少个字节不处理,通常是将协议头部跳过,只将消息体中内容传输到下游时使用

boolean failFast

是否快速失败。

boolean discardingTooLongFrame

是否吞没(跳过)大帧包。

long tooLongFrameLength

当前在处理吞没大包的实际大小。

long bytesToDiscard

下一次解码之前,需要先忽略的字节数,当遇到超过maxFrameLength的包时使用。

上面的属性如果不太好理解,没关系,因为本节的最后会有两张图勾画出协议的全貌(用图示的方式勾画出各个属性的位置与含义)

2.2 decode 方法详解

接下来我们来看一下其decode方法,通过阅读源码的方法来理解其内部的工作原理。

LengthFieldBasedFrameDecoder#decode

Step1:跳过无效数据包的处理逻辑。如果discardingTooLongFrame为true,表示正在处理大于****maxFrameLength的包,需要跳过这个超长的包,不对其解码,由于数据是陆续到达累积缓存区,并不能一次跳过整个无效包,故需引入 bytesToDiscard 变量,用于记录本次能跳过的字节,当 bytesToDiscard 为 0后表示一个无效包已全部跳过,需要处理正常数据包,此时discardingTooLongFrame 会重置为 false。

Step2:如果累积缓冲区的可读字节大小小于length字段的结束偏移量,返回null,结束解码,说明该累积缓存区中的数据还不完整。

Step3:尝试从累积缓存区中获取包的长度。其中表示 lengthFiedlOffset 表示长度字段的其实偏移量,在结合长度字段的长度 lengthFieldLength ,再结合字节序列**(大端序列、小端序列)**。

Step4:这里是包长度超过协议允许的最大包长度时的处理逻辑,在这里大家先姑且跳过 lengthAdjustment 属性的含义。

如果当前累积缓存区中的可读字节大于 frameLength,大于当前包的长度,可以通过调用 skipBytes 方法跳过这包。

如果当前累积缓存区的可读自己小于 frmaeLength,需要分多次跳过,故先将累积区中的数据全部跳过,然后通过 bytesToDiscard 记录还需要跳过的字节数。

Step5:如果累积缓存区中的数据不包含一个完整的包,返回null,结束本次解码,等待更多的数据包的到来。

Step6:通过 ByteBuf 的 slince 方法,提取一个完整的包长度,解码出完整的数据包,完成一个数据包解码。

2.3 图解 LengthFieldBasedFrame 协议

在Netty 的

LengthFieldBasedFrameDecoder 中有一个 lengthAdjustment 属性,可以是正数,也可以是负数,其使用的代码片段如下:

frameLength += lengthAdjustment + lengthFieldEndOffset

lengthAdjustment 长度调整字段,可以为正数,也可以为负数,主要的作用是 长度字段中的值是否包含 Header 长度本身,严格意义上来说应该是包含 长度字段之前的字节序列。

1、lengthAdjustment > 0

2、lengthAdjustment < 0

在大多数情况下,length字段表示消息正文的长度,但是有些协议,其长度表示的是整个消息的长度,故Netty为了适配这种情况,可以通过 lengthAdjustment 设置为负数,来调节数据帧的大小。

总结:lengthAdjustment 的出现是Netty为了适配现有的协议而设计出来的字段,即 Netty

LengthFieldBasedFrameDecoder 是为了i给 header + body ,并且基于长度字段的协议一种通用的解决方案,可以通过 lengthAdjustment 来准确表示数据帧(业务数据的长度),这里是一种逆向思维

3、协议设计子类的最佳实践

最佳实践:

LengthFieldBasedFrameDecoder 的 decode 方法的职责是从二进制流中解码出一个完整的数据包,其返回类型还是 ByteBuf,故自定义的编码解码器的 decode 方法就是先调用父类的 decode 方法 得到 ByteBuf ,然后对 ByteBuf 中的数据解码出对象。

LengthFieldBasedFrameDecoder 并不负责将 ByteBuf 转换为协议对象,而是从二进制流中解码出一个数据帧,而将ByteBuf 转换为协议对象的职责由其子类实现,通常的编码风格如下:

资源获取:
大家 点赞、收藏、关注、评论啦 、 查看 👇🏻 👇🏻 👇🏻 微信公众号获取联系方式 👇🏻 👇🏻 👇🏻
精彩专栏推荐订阅:下方专栏 👇🏻 👇🏻 👇🏻 👇🏻
每天学四小时:Java+Spring+JVM+分布式高并发,架构师指日可待

这篇关于揭秘通信协议设计的奥妙,作为面试官我都看蒙了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/375011

相关文章

Python中的可视化设计与UI界面实现

《Python中的可视化设计与UI界面实现》本文介绍了如何使用Python创建用户界面(UI),包括使用Tkinter、PyQt、Kivy等库进行基本窗口、动态图表和动画效果的实现,通过示例代码,展示... 目录从像素到界面:python带你玩转UI设计示例:使用Tkinter创建一个简单的窗口绘图魔法:用

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

揭秘世界上那些同时横跨两大洲的国家

我们在《世界人口过亿的一级行政区分布》盘点全球是那些人口过亿的一级行政区。 现在我们介绍五个横跨两州的国家,并整理七大洲和这些国家的KML矢量数据分析分享给大家,如果你需要这些数据,请在文末查看领取方式。 世界上横跨两大洲的国家 地球被分为七个大洲分别是亚洲、欧洲、北美洲、南美洲、非洲、大洋洲和南极洲。 七大洲示意图 其中,南极洲是无人居住的大陆,而其他六个大洲则孕育了众多国家和

三国地理揭秘:为何北伐之路如此艰难,为何诸葛亮无法攻克陇右小城?

俗话说:天时不如地利,不是随便说说,诸葛亮六出祁山,连关中陇右的几座小城都攻不下来,行军山高路险,无法携带和建造攻城器械,是最难的,所以在汉中,无论从哪一方进攻,防守方都是一夫当关,万夫莫开;再加上千里运粮,根本不需要打,司马懿只需要坚守城池拼消耗就能不战而屈人之兵。 另一边,洛阳的虎牢关,一旦突破,洛阳就无险可守,这样的进军路线,才是顺势而为的用兵之道。 读历史的时候我们常常看到某一方势

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

无线领夹麦克风什么牌子好用?揭秘领夹麦克风哪个牌子音质好!

随着短视频行业的星期,围绕着直播和视频拍摄的电子数码类产品也迎来了热销不减的高增长,其中除了数码相机外,最为重要的麦克风也得到了日益增长的高需求,尤其是无线领夹麦克风,近几年可谓是异常火爆。别看小小的一对无线麦克风,它对于视频拍摄的音质起到了极为关键的作用。 不过目前市面上的麦克风品牌种类多到让人眼花缭乱,盲目挑选的话容易踩雷,那么无线领夹麦克风什么牌子好用?今天就给大家推荐几款音质好的

负债不再是障碍?银行信贷“白名单“揭秘

谈及银行信贷产品,常闻有言称存在无需考量负债与查询记录之奇品,此等说法十有八九为中介诱人上钩之辞。轻信之下,恐将步入连环陷阱。除非个人资质出类拔萃,如就职于国央企或事业单位,工龄逾年,五险一金完备,还款能力卓越,或能偶遇线下产品对查询记录稍显宽容,然亦非全然无视。宣称全然不顾者,纯属无稽之谈。 银行非慈善机构,不轻易于困境中援手,更偏爱锦上添花之举。若无坚实资质,即便求助于银行亦难获青睐。反

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

SprinBoot+Vue网络商城海鲜市场的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质创作者,全网30w+