自定义_如何自定义协议

前言

何为自定义协议,其实是相对标准协议来说的,这里主要针对的是应用层协议;常见的标准的应用层协议如http、ftp、smtp等,如果我们在网络通信的过程中不去使用这些标准协议,那就需要自定义协议,比如我们常用的RPC框架(dubbo,thrift),分布式缓存(redis,memcached)等都是自定义协议;本文就来讲讲如何去自定义私有协议,在此之前我们先考虑一下为什么要自定义协议。

为什么要自定义协议

直接使用标准的协议好处是显而易见的,我个人理解的几点优点:

  • 既然是标准协议说明已经成为了标准,这样很多系统就可以直接对接,无缝集成;

  • 协议最重要的一点就是编码解码,标准协议往往有现成的编码解码包,直接拿来使用,减少开发时间;

  • 有很多围绕标准协议的第三方测试工具,可以很方便的进行测试;

既然有这么多优点那我们为什么还要去自定义协议,大致出于以下几点考虑:

  • 既然是标准协议,往往兼顾的东西比较多,导致协议数据相对来说比较大,这样可能在一些追求性能,流量的系统中不能容忍;

  • 标准协议有很多,没有哪一种协议可以适用任何场景中,所以如果在某个场景中还没有既定的标准协议,这时候会有各种私有协议;

  • 自定义协议只要双方约定好数据结构就行,不具有通用性,理论上来说会更加安全一点,当然现在很多标准协议都有安全版本,比如https,sftp等等;

以上只是个人的一点理解,欢迎大家补充;关于如何去自定义协议,其实可以去多参考一些主流的标准协议或者私有协议,其实有很多共同点可以去借鉴;下面先简单看看那些主流的协议;

主流协议

下面分别看看一些主流的标准协议或者私有协议都是如何去定义自己的数据结构的,对我们有非常好的借鉴意义;

http协议

http协议大家最熟悉不过了,全称叫超文本传输协议,整个请求报文可以分为三个部分分别是:请求行,请求报头,请求正文;

  • 请求行

GET /test.html HTTP/1.1 (CRLF换行)
  • 请求报头

Accept-Encoding: gzip, deflate
Content-Length: 38
Content-Encoding: gzip
...

请求包头有很多,每一个代表了各自的含义,这边就不一一列出,我们这里更加关注整个报文的结构;

  • 请求正文

这个只有在POST请求的时候才有正文,里面存放业务数据,比如常见的json文本串;具体正文的长度可以根据消息头中的Content-Length来决定;

dubbo协议

dubbo协议格式可以直接参考官网提供的如下图片: 87d7ef04c4d83d82f2df11535c685737.png 看上图其实整个协议数据包也大致分为两个部分:固定部分和可变部分,或者叫消息头和消息体;固定部分一共是4+8+4=16个字节,具体如下所示:

header{
Magic High = 8bit; //魔数高位
Magic Low = 8bit; //魔数低位
Req/Res = 1bit; //标识是请求或响应
2 Way = 1bit; //标记是否期望从服务器返回值
Event = 1bit; //标识是否是事件消息
Serialization ID = 5bit; //标识序列化类型
Status = 8bit; //标识响应的状态
Request ID = 64bit; //标识唯一请求
Data Length = 32bit; //序列化后的内容长度
}

可变部分根据固定部分中的Data Length来确定长度;

redis协议

Redis的客户端与服务端采用叫做 **RESP(Redis Serialization Protocol)**的网络通信协议交换数据,相对来说还是比较简单的,以下是这个协议的一般形式:

*< 参数数量 > CR LF
$< 参数 1 的字节数量 > CR LF
< 参数 1 的数据 > CR LF
...
$< 参数 N 的字节数量 > CR LF
< 参数 N 的数据 > CR LF

以上大致介绍了三种比较有代表性的协议,虽然说每种协议都有各自的使用场景,但是如果我们自己去定义协议,还是有一些相通的东西;

如何自定义协议

下面我们重点看看去自定义协议有哪些需要我们关注的点,以下是本人根据自己的理解整理了如下关注点:

  • 完整的数据包

  • 协议号

  • 消息头标识

  • 业务数据

  • 预留字段

下面分别逐一详细介绍:

完整的数据包

我们平时经常讲数据包,但是TCP其实只有流的概念,并没有数据包的概念;那很重要的一点就是我们的程序怎么知道现在的业务数据已经接受全部接收完了,可以作为一个完整的数据包去处理了,如果不去做处理的话就会出现我们常说的半包和粘包问题;主流的的处理方式大致有这么两种:

  • 在消息头部加上数据包长度描述,比如在http协议和dubbo协议中出现的dataLength字段;

  • 用特殊的字符串作为数据包的结尾,这样我们在接受数据的时候接受到预定的特殊字符串就表示数据包完整了;

协议号

可能不同的协议有不同的叫法,我这里把它叫做协议号,个人理解就是根据这个协议号,服务器端知道去执行什么逻辑;比如http协议请求行中的/test.html,dubbo协议中的服务名+版本号,redis中的具体要执行什么key;

消息头标识

这个是否需要还是要看各自的场景,比如redis协议足够简单,无需任何标识,所有的东西都是双端约定好的;但是其他很多协议还是有一些需要的,除了上面说到的可以在消息头中指定dataLength,其实还有很多其他的东西可以指定比如:

  • 业务数据格式:文本格式,json格式,html格式等等;

  • 压缩格式:可能为了追求流量包大小对数据包进行压缩,gzip、deflater、snappy等;

  • 加密算法:可能需要对我的业务数据进行加密处理,保证业务数据的安全性AES、DES等;

业务数据

业务数据往往在整个数据包中是最大的,同时也是大小可变的部分;我们上面所做的这些其实都是在为业务数据服务,业务数据需要在网络传输,最重要的一点就是序列化,一般就以下两种方式:

  • 文本方式:序列化文本文档text,或者json串,xml格式等;

  • 二进制方式:常见的比如protobuf,thrift,kyro等;

预留字段

是否需要预留字段这个得看情况,比如http协议整个消息头是可变的,每一行一个标识,知道读取到空行,表示消息头结束下面就是正文了,可以理解为http使用了两种方式来保证完整包,消息头使用特殊字符结尾,正文使用在消息头中指定dataLength;这种方式其实它的整个扩展性是非常好的;另外一种像dubbo这样,其实它的头部相当于已经固定好了16个字节,这种情况下是否可以预留几个字节防止后面的变更;

总结

自定义协议其实在我们真正的工作中还是很少能接触到的,更多的其实还是去实现业务,但是我们系统无时无刻不在和各种应用层协议打交道,如果我们了解了各种协议,在系统出现问题时可以做抓包分析;另外像我们常用的数据库中间件、缓存中间件等,都需要对协议都充分的了解,然后去实现代理。

感谢关注

可以关注微信公众号「回滚吧代码」,第一时间阅读,文章持续更新;专注Java源码、架构、算法和面试。

- END -

往期推荐

RPC框架设计概要

《大厂面试》之线上故障排查

《生产事故》之反射引发的宕机问题

abb420df4f63b012ac59654e408c092c.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/476059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

校验json格式_格式化展示,校验错误,编辑JSON,这几个JSON工具一定不能错过

今天给大家介绍几个常用JSON的工具&#xff0c;基本上能满足你工作中对JSON的所有需求google插件 JSONView安装好插件后&#xff0c;格式化接口返回的JSON&#xff0c;还能展开节点和关闭节点&#xff0c;超级方便格式化本地JSON&#xff0c;检验错误JSON Viewer网页版将杂乱的…

推荐系统常用评价指标和代码实现

评价指标 Recall 名称&#xff1a; 召回率&#xff08;真阳性率&#xff09; 意义&#xff1a;在推荐系统中&#xff0c;我们只关心正确推荐的有多少&#xff0c;也就是用户真实喜欢的&#xff0c;并不会关心推荐错的&#xff0c;所以我们用召回率&#xff0c;而不是准确率&a…

python timeit用法_十大Python开发技巧

Python开发指南, 超级实用足以让您震撼> Photo by Christina Morillo from StockSnap时不时地&#xff0c;当我了解Python的新功能时&#xff0c;或者我发现其他一些人不知道该功能时&#xff0c;我会记下它。在过去的几周中&#xff0c;我最近了解或实现了一些有趣的功能-S…

python编程中的经验(一直更新)

文章目录1. python基础语法1.1 怎么让两个list或者其它可以迭代的放到一起1.2 random.choice(x, n, replaceTrue) numpy中从某个数据集中选择1.3 如何根据key返回字典的value1.4 The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all…

Cairngorm初学者入门教程 第六节--Cairngorm中Command利用Delegate与Service连接

在上一节&#xff0c;我们利用FrontController 去映射 Event与Command 在这一节我们主要针对Command这部分动作做介紹。在RIA应用程序中&#xff0c;不可或缺的部份就是跟后台服务器连接进行数据传递。Command通过Delegate去做Services的部份(包含Remoting,WebServices,…等) C…

3d点击_3D打印服务加工在医疗器械行业的应用

3D打印技术如今已经很常见的出现在了我们日常的制造生产中。普通的3D打印机从最开始的几万块到如今的几千块&#xff0c;设备价格的降低也使得3D打印技术普及率的增加&#xff0c;而技术的普及也推动着技术的发展。3D打印开始应用到许多行业当中&#xff0c;下面悟空打印坊3D打…

所有算法库的使用(sklearn,scipy)

文章目录1. sklearn1.1 sklearn.preprocessing 之 fit 和 transform 以及 fit_transform1.2 算法之 fit 和 predict和predict_proba1.3 predict_proba1.4 各种评测指标1.4.1 R2R^2R21.4.2 准确度、精准率、召回率1.4.3 平均绝对误差(MAE)和均方误差(MSE)1.5 特征缩放 StandardS…

android aar保存图片文件异常_我去!合并AAR时踩坑了!

点击上方“刘望舒”&#xff0c;马上关注&#xff0c;早上8:42推送真爱&#xff0c;请置顶或星标作者: leeon7https://www.jianshu.com/p/8f7e32015836背景在输出Android模块时&#xff0c;有时会因为个别原因(比如来自业务的不可抗力)&#xff0c;要求将模块打包成一个文件提供…

与kylin_Kylin 迁移到 HBase 实践在小米的实践

背景小米Kylin生产环境部署的是基于社区2.5.2修改的内部版本&#xff0c;所依赖HBase集群是一个公共集群&#xff0c;小米内部很多离线计算服务共享使用该HBase集群。由于Kylin已经产生超过6000张HBase表&#xff0c;给HBase的metadata管理造成了不小的压力&#xff0c;HBase m…

LeetCode 1227. 飞机座位分配概率(DP+数学归纳法)

1. 题目 有 n 位乘客即将登机&#xff0c;飞机正好有 n 个座位。第一位乘客的票丢了&#xff0c;他随便选了一个座位坐下。 剩下的乘客将会&#xff1a; 如果他们自己的座位还空着&#xff0c;就坐到自己的座位上&#xff0c; 当他们自己的座位被占用时&#xff0c;随机选择…

LeetCode 1025. 除数博弈(动态规划)

1. 题目 爱丽丝和鲍勃一起玩游戏&#xff0c;他们轮流行动。爱丽丝先手开局。 最初&#xff0c;黑板上有一个数字 N 。在每个玩家的回合&#xff0c;玩家需要执行以下操作&#xff1a; 选出任一 x&#xff0c;满足 0 < x < N 且 N % x 0 。用 N - x 替换黑板上的数字…

BN / LN / IN / GN /

链接 但是代码不敢苟同! 所以自己写了两种代码! 由于这只是测试, 并不是用来训练, 所以α和β参数就没有加! def BN(inputs):c inputs.shape[1]for i in range(c):channel inputs[:,i,:,:]mu np.mean(channel)var np.var(channel)channel_new ((channel - mu)/(np.sqrt(…

中文验证码 php_还在苦恼验证码怎么实现?看看这个验证码组件合集,你想要的都有...

随着安全性的要求越来越高&#xff0c;如今的验证码已经不再是简单的四个数字或者字母了&#xff0c;更复杂的图形验证码和行为验证码已经成为了更流行的趋势&#xff0c;但更难的实现也让很多开发者头秃&#xff0c;Gitee 已经替你们想到了这一点。不多说了&#xff0c;下面这…

reload端口 tomcat_tomcat上部署网站的三种方式

一、利用webapps文件夹自动部署这是最简单的方式&#xff0c;只要将网站直接拷贝到&#xff1a;tomcat根目录下的webapps文件夹里举例&#xff1a;helloworld文件夹下创建里index.html文件&#xff0c;然后把helloworld文件夹移动到tomcat根目录下webapps文件夹里&#xff0c;重…

不能用蛮力法解决的问题_溆浦事蒙汉:脱贫攻坚绝不能心浮气躁骄傲自满疲倦厌战...

脱贫攻坚绝不能心浮气躁骄傲自满疲倦厌战——蒙汉到卢峰镇检查“四支队伍”集村部工作情况检查南华山村“四支队伍”集村部工作情况与大潭村贫困户舒采米座谈红网溆浦讯(记者 伍交才)8月28日&#xff0c;市人大常委会副主任、县委书记蒙汉到卢峰镇南华山村、大潭村检查“四支队…

mock模拟接口测试 vue_vue+mock.js实现前后端分离

之前都是介绍在普通项目中使用mock.js&#xff0c;那么本次就来介绍一下在vue中使用mock.js实现前后端分离。安装&#xff1a;npm install mockjs这里先写个小案例介绍一下具体使用&#xff0c;写法不规范&#xff0c;仅供参考。然后案例讲完后我们讲具体的规范使用那么一起来看…

mysql slow log 分析工具_mysql slow log分析工具的比较

mysql 中的 slow log 是用来记录执行时间较长(超过 long_query_time 秒)的 sql 的一种日志工具。启用 slow log在 my.cnf 中设置[mysqld]slow_query_logonslow_query_log_filemysql-slow重启 MySQL 服务。五款常用工具mysqldumpslowmysqlslamyprofimysql-explain-slow-logmysql…

利用寄存器进入栈值交换

代码 varA, B: Word;beginA :1; B :2; asmmov ax, a //赋值 mov bx, b push ax //进栈 push bx pop ax //退栈 pop bx mov a, ax //利用栈先进后出, ax已退栈, 寄存器里的值为原bx 的值 mov b, bx //利用栈先进后出, bx已退栈, 寄存…

处理Excel,填充空白区域

在企业应用开发中经常是业务人员提供Excel的数据源&#xff0c;而开发人员将Excel数据导入到数据库中&#xff0c;然后在数据库中进行处理。在Excel中为了表示一种层次和所属关系&#xff0c;很多时候会产生很多空白的单元格。比如一个CRM数据&#xff0c;里面有销售团队、销售…

LeetCode 901. 股票价格跨度(单调栈)

1. 题目 编写一个 StockSpanner 类&#xff0c;它收集某些股票的每日报价&#xff0c;并返回该股票当日价格的跨度。 今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数&#xff08;从今天开始往回数&#xff0c;包括今天&#xff09;。 例如&#xff0c…