这是接上一篇文章《RSF 分布式服务框架设计》以后的续做,主要是 Hasor-RSF 协议层的设计。 sql
RSF 的协议层设计能够很复杂也能够很简单。复杂是指这一层能够嵌套多层协议栈,让 RSF 的交互数据能够跑在各类协议之上,例如:HTTP、RTMP、也能够跑在相对底层的协议例如:TCP、UDP。 安全
RSF 在协议层的设计上须要保留可能未来嵌套其它协议的支持,但不要设计的过于复杂。所以 RSF 的协议层的实现应该被分为两层,以下:
服务器
位于底层的传输协议能够是 TCP、UDP、RTMP、HTTP、等等各种听过或者没听过的网络协议。对于这些传输协议的要求只有一个 -- 那就是能够传输 RSF 数据包。 网络
在 RSF 初期彻底能够忽略传输协议这一层的设计,只要将 RSF 数据包丢到网络上而后远程程序接收到便可。由于传输协议无外乎是至关于给 RSF 数据包套了一层马甲,而这层马甲在初期做用并不大,能够随着完善逐步丰富。 数据结构
接下来就是最关键的部分RSF 数据包的格式了,RSF 数据包的大致格式是“定长包头 + 变长包体”这种形式。而且协议被设计成为无状态的。 并发
RSF数据交互形式: 框架
RSF交互协议采用(请求/响应)这种模式,客户端发送某种类型的RSF数据包,服务器响应这种类型的请求。不须要握手协议。同时也是无状态的。 分布式
RSF数据包格式: spa
请求.net
* RSF 1.0 Request 协议 * --------------------------------------------------------bytes =13 * byte[1] version RSF版本(0xC1 or 0x81) * byte[8] requestID 请求ID * byte[1] keepData 保留区 * byte[3] contentLength 内容大小(max ~ 16MB) * --------------------------------------------------------bytes =10 * byte[2] servicesName-(attr-index) 远程服务名 * byte[2] servicesGroup-(attr-index) 远程服务分组 * byte[2] servicesVersion-(attr-index) 远程服务版本 * byte[2] servicesMethod-(attr-index) 远程服务方法名 * byte[2] serializeType-(attr-index) 序列化策略 * --------------------------------------------------------bytes =1 ~ 1021 * byte[1] paramCount 参数总数 * byte[4] ptype-0-(attr-index,attr-index) 参数类型1 * byte[4] ptype-1-(attr-index,attr-index) 参数类型2 * ... * --------------------------------------------------------bytes =1 ~ 1021 * byte[1] optionCount 选项参数总数 * byte[4] attr-0-(attr-index,attr-index) 选项参数1 * byte[4] attr-1-(attr-index,attr-index) 选项参数2 * ... * --------------------------------------------------------bytes =6 ~ 8192 * byte[2] attrPool-size (Max = 2047) 池大小 0x07FF * byte[4] att-length 属性1大小 * byte[4] att-length 属性2大小 * ... * --------------------------------------------------------bytes =n * dataBody 数据内容 * bytes[...]
响应
* RSF 1.0 Response 协议 * --------------------------------------------------------bytes =13 * byte[1] version RSF版本(0xC1 or 0x81) * byte[8] requestID 包含的请求ID * byte[1] keepData 保留区 * byte[3] contentLength 内容大小(max ~ 16MB) * --------------------------------------------------------bytes =8 * byte[2] status 响应状态 * byte[2] serializeType-(attr-index) 序列化策略 * byte[2] returnType-(attr-index) 返回类型 * byte[2] returnData-(attr-index) 返回数据 * --------------------------------------------------------bytes =1 ~ 1021 * byte[1] optionCount 选项参数总数 * byte[4] attr-0-(attr-index,attr-index) 选项参数1 * byte[4] attr-1-(attr-index,attr-index) 选项参数2 * ... * --------------------------------------------------------bytes =6 ~ 8192 * byte[2] attrPool-size (Max = 2047) 池大小 * byte[4] att-length 属性1大小 * byte[4] att-length 属性2大小 * ... * --------------------------------------------------------bytes =n * dataBody 数据内容 * bytes[...]
上面列出了RSF在网络通讯中所使用的数据包结构。
RSF数据包的主要结构是: “Head + ContentLength + Content”,这种包结构能够很方便的在底层网络框架上予以解析并且简单易懂。相比较淘宝 HSF2.0 的协议 RSF 的扩展性还算蛮强的。
Head 头:
RSF 的协议头采用 13 字节固定长度,其中包括了RSF在通讯上的 5 个基本数据(RSF协议标记、协议版本、包类型、请求ID,数据包长度)。
第一个字节中RSF目前规定只有:“0xC1” 和 “0x81” 两个值。其中第1个二进制位用于表示RSF数据包,第2个二进制位用来表示请求或者响应,后面6个二进制位用来表示RSF协议版本。
因此有了:“0x80”能够用来检验是否为RSF数据包、“0xC0”用来表示RSF 请求数据包、“0x80”用来表示RSF响应数据包。因此依照这个规则“B2、F2、DA、FF”等值都是合法的,不过由于目前RSF协议版本只有1.0,因此只有 0xC1 和 0x81 是有效的。
接下来8个字节用来表示一个 long 值,这个值是请求ID。请求ID的做用是区分同一客户端在并发调用的状况下区分不一样调用而设计的。
在接下来的 1 个字节为保留位。随后的 3 个字节表示一个 int 类型,这个值表示的是 RSF 头以后的 RSF 数据包总长度。这样就限制了RSF数据包大小最约 16MB。
Content 结构:
RSF 的包体中协议格式和传输的数据是分离设计的,这种设计会让协议自己的结构显得很是清晰。全部的属性值都会保存在属性池中,而且以其在属性池中位值加以替代。例如:
服务名为:“org.example.hello.MyService”的信息转换为二进制以后,将其放入属性池,而后用其在属性池中的位置加以表示(2字节 short 类型)。
此外对于键值这种结构的数据将会采用(4字节来表示),其中 key 由前两个字节表示,value用后两位字节表示。而这 4个字节刚好可使用 int 类型来表示。
依照上面两个规则就造成了 RSF 请求响应的数据结构。
最后是属性池的设计,属性池的最大容量是 65535 条。依照现有的RSF协议规定根本没法达到这个量级,因此是十分安全的。
属性池中的数据都是 4 字节,用来表述内容大小。例如上面那个服务名其在属性池中的值是 27。
最后 dataBody 部分将会按照属性池中的顺序一次将属性内容排列下去。
假设提取位于属性池 3 号位置的属性属性值是 23,其前面两个属性大小均为 10 字节,那么 3号属性的实际位置就是 dataBody区域的 20~43 位置的数据。
属性池的 0 号属性:
属性池中 0 号属性是 RSF 协议中规定的固定属性,其属性值为 0。做为 0 长度的属性在 dataBody 区域是不会产生任何数据输出。