何为自定义协议,实际上是相对标准协议来讲的,这里主要针对的是应用层协议;常见的标准的应用层协议如http、ftp、smtp等,若是咱们在网络通讯的过程当中不去使用这些标准协议,那就须要自定义协议,好比咱们经常使用的RPC框架(dubbo,thrift),分布式缓存(redis,memcached)等都是自定义协议;本文就来说讲如何去自定义私有协议,在此以前咱们先考虑一下为何要自定义协议。html
直接使用标准的协议好处是显而易见的,我我的理解的几点优势:面试
既然有这么多优势那咱们为何还要去自定义协议,大体出于如下几点考虑:redis
以上只是我的的一点理解,欢迎你们补充;关于如何去自定义协议,其实能够去多参考一些主流的标准协议或者私有协议,其实有不少共同点能够去借鉴;下面先简单看看那些主流的协议;算法
下面分别看看一些主流的标准协议或者私有协议都是如何去定义本身的数据结构的,对咱们有很是好的借鉴意义;数据库
http协议你们最熟悉不过了,全称叫超文本传输协议,整个请求报文能够分为三个部分分别是:请求行,请求报头,请求正文;json
GET /test.html HTTP/1.1 (CRLF换行)
Accept-Encoding: gzip, deflate Content-Length: 38 Content-Encoding: gzip ...
请求包头有不少,每个表明了各自的含义,这边就不一一列出,咱们这里更加关注整个报文的结构;segmentfault
这个只有在POST请求的时候才有正文,里面存放业务数据,好比常见的json文本串;具体正文的长度能够根据消息头中的Content-Length来决定;缓存
dubbo协议格式能够直接参考官网提供的以下图片:
看上图其实整个协议数据包也大体分为两个部分:固定部分和可变部分,或者叫消息头和消息体;
固定部分一共是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的客户端与服务端采用叫作 RESP(Redis Serialization Protocol)的网络通讯协议交换数据,相对来讲仍是比较简单的,如下是这个协议的通常形式:
*< 参数数量 > CR LF $< 参数 1 的字节数量 > CR LF < 参数 1 的数据 > CR LF ... $< 参数 N 的字节数量 > CR LF < 参数 N 的数据 > CR LF
以上大体介绍了三种比较有表明性的协议,虽说每种协议都有各自的使用场景,可是若是咱们本身去定义协议,仍是有一些相通的东西;
下面咱们重点看看去自定义协议有哪些须要咱们关注的点,如下是本人根据本身的理解整理了以下关注点:
下面分别逐一详细介绍:
咱们平时常常讲数据包,可是TCP其实只有流的概念,并无数据包的概念;那很重要的一点就是咱们的程序怎么知道如今的业务数据已经接受所有接收完了,能够做为一个完整的数据包去处理了,若是不去作处理的话就会出现咱们常说的半包和粘包问题;主流的的处理方式大体有这么两种:
可能不一样的协议有不一样的叫法,我这里把它叫作协议号,我的理解就是根据这个协议号,服务器端知道去执行什么逻辑;好比http协议请求行中的/test.html,dubbo协议中的服务名+版本号,redis中的具体要执行什么key;
这个是否须要仍是要看各自的场景,好比redis协议足够简单,无需任何标识,全部的东西都是双端约定好的;可是其余不少协议仍是有一些须要的,除了上面说到的能够在消息头中指定dataLength,其实还有不少其余的东西能够指定好比:
业务数据每每在整个数据包中是最大的,同时也是大小可变的部分;咱们上面所作的这些其实都是在为业务数据服务,业务数据须要在网络传输,最重要的一点就是序列化,通常就如下两种方式:
是否须要预留字段这个得看状况,好比http协议整个消息头是可变的,每一行一个标识,知道读取到空行,表示消息头结束下面就是正文了,能够理解为http使用了两种方式来保证完整包,消息头使用特殊字符结尾,正文使用在消息头中指定dataLength;这种方式其实它的整个扩展性是很是好的;
另一种像dubbo这样,其实它的头部至关于已经固定好了16个字节,这种状况下是否能够预留几个字节防止后面的变动;
自定义协议其实在咱们真正的工做中仍是不多能接触到的,更多的其实仍是去实现业务,可是咱们系统无时无刻不在和各类应用层协议打交道,若是咱们了解了各类协议,在系统出现问题时能够作抓包分析;另外像咱们经常使用的数据库中间件、缓存中间件等,都须要对协议都充分的了解,而后去实现代理。
能够关注微信公众号「 回滚吧代码」,第一时间阅读,文章持续更新;专一Java源码、架构、算法和面试。