# net_protocol_builder **Repository Path**: pipiaha/net_protocol_builder ## Basic Information - **Project Name**: net_protocol_builder - **Description**: 网络协议生成工具 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2017-03-23 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # net_protocol_builder ## 1. 使用环境 安装`jdk`或者jre 1.8 及以上 ## 2. 目录结构 `protocol`文件夹:存放协议描述文件,可根据运行命令参数自定义 `template`文件夹:存放生成语言模板,此文件夹要放在运行路径-root之下(详见 3.6 运行命令); `lib`文件夹:生成工具的依赖项 ## 3. 协议描述文件(.ptl) 想要构建一套自己的通信协议内容,就要从编写协议描述文件开始。协议描述文件以.ptl结尾,由消息(`message`)和自定义结构(`struct`)构成。每一个.ptl文件构成了一个协议模块。 消息(`message`)根据发起方(客户端/服务器)的不同归在不同的消息方向下,消息(`message`)和自定义结构(`struct`)中包含了0或多个成员; 消息(`message`)和自定义结构(`struct`)的成员可以是基本类型,也可以是自定义结构(`struct`)类型。 ### 3.1 消息 message 一个`message`即为一个消息。作为通信协议中一次传输中的基本单位。 > * 它包含若干成员,在传输时会被序列化/反序列化; > * 一个消息应拥有整个协议上下文中全局唯一的名字; > * 消息可继承其他消息(`message`)或自定义结构(`struct`) ``` 语法 message ${name} [: ${parent}] { [ // ${comment}] ...message的成员 int field1; SomeCustomStruct customField; ... } ``` 语法中的`SomeCustomStruct` 是一个自定义结构(`struct`)。 ### 3.2 自定义结构 struct `struct` 用于消息协议中的自定义类型,当有相较基本类型更为复杂的数据要描述和传输时,通常需要定义一个`struct`。 > * `struct` 的语法和 `message` 除关键字外基本相同; > * `struct`可以作为另一个 `struct` 或 `message` 的成员,用于构成更为复杂的消息结构体定义; > * 一个自定义结构应拥有整个协议上下文中全局唯一的名字; ``` 语法 struct ${struct_name} [: ${its_parent}] { // ${comment} ...struct 的成员 string someString; SomeCustomStruct customField; ...struct 的其他成员 } ``` ### 3.3 模块 module(.ptl) 构建一个协议描述的基本单位是消息(`message`)和(`struct`)。将相关的(`message`)和(`struct`)放在同一文件内, 这个文件(*.ptl)便是一个模块(`module`)。 模块主要作用是决定生成协议编号及顺序并按照功能模块划分各个消息组。 ### 3.4 语法 #### 3.4.1 消息方向 C2S/S2C 消息分为 客户端->服务器(C2S) 和 服务器->客户端(S2C) 两个方向,分别用 > client to server: 和 > server to client: 两个关键字表示。关键字单独占用一行, 消息(`message`)写在关键字后表示此消息属于其代表的方向; 自定义结构(`struct`)不受方向关键字影响,不属于任何方向。 ``` 语法 client to server: message SomeRequest { // 注释 string someString; SomeCustomStruct customField; list listsOfStuff; } ... 其他message 或 struct server to client: message LoginResponse { // 注释 int code; string message; } ``` #### 3.4.2 自定义结构 struct #### 3.4.3 message #### 3.4.4 type 协议生成工具支持基本数据类型和几种基本集合类型,以及自定义结构(`struct`)类型。 基本类型包括: * `int` 整型 4字节 * `long` 长整型 8字节 * `short` 短整型 2字节 * `byte` 字节型 1字节 * `bool` 布尔型 1字节 * `float` 浮点型 4字节 * `double` 双精度浮点型 8字节 * `string` 字符串型 列表类型包括: * `list` 列表 如整型列表 `list` * `set` 集合 如字符串集合 `set` * `map` hashMap 如 `map` 自定义结构类型: * 直接使用自定义结构名称作为类型 如 `SomeStruct struct;` #### 3.4.5 注释 comment 使用行注释 // 定义在 消息(`message`)和(`struct`)声明行的注释会作为消息(`message`)和(`struct`)的生成内容注释; 定义在 成员行;后的注释将作为生成内容中该成员的注释; 如: ``` struct SomeNestedStruct { // comment of nested struct int a;// comment of a long b; } ``` #### 3.4.6 继承 inherit 协议生成上下文为消息(`message`)和(`struct`)提供了单继承功能。 消息(`message`)和(`struct`)可以相互继承,作为子类将默认获得父类的所有成员。 继承关键字类似C++/C#,使用 `:` 。如: ``` message QueryAllStudentsResponse : Response { string message; list students; } message Response { int code; } ``` `QueryAllStudentsResponse` 继承了消息`Response`,故而除了本身的两个成员外, 还拥有父消息的`code`。 > * 父消息/父结构中的成员将优先进行序列化和反序列化操作; > * 如果父子之间存在同名成员,父成员将被覆盖; **注意!当前版本Lua的反序列化过程未解决重名问题,如果使用Lua语言,尽量避免父子之间出现重名** > * 仅支持单继承,即只有一个父类;继承关系不得出现循环,如 A继承B,B继承C,C则不可再继承A或者B; ### 3.5 模块顺序(.order) 有了一系列模块文件(.ptl),协议的基本内容已经搞定; 为了方便传输和识别,我们将为每一个消息(`message`)定义一个全局唯一的协议号, 而模块顺序文件(*.order)就负责规定各个模块获得协议号的顺序。 如,当前有三个模块 player.ptl, room.ptl和fight.ptl, 顺序文件内容即为要生成的各个模块名略去文件后缀,按行排列,重复内容以最先出现为准。 例 `module.order`: ``` fight player room ``` > * 没有出现在顺序文件中的模块将不会参与代码生成;不存在的模块会触发代码异常导致运行中断。 > * 模块顺序文件分为主文件和追加文件,在启动后追加文件内容会按照追加顺序依次补充到主顺序文件中,重复内容以最先出现的为准。 > * 追加文件是可选项。 ### 3.6 运行命令 > * `-root` 运行根目录,决定其他相对目录的位置,*可选*,不使用则默认为当前运行路径; > * `-src` ptl文件存放目录。相对路径,在-root之下;*必须指定*,用于定位协议源文件; > * `-gen` 生成代码存放路径。相对路径,在-root之下;*必须指定*,用于存放生成的内容; > * `-lang` 定义生成目标语言,*必须指定*,目前支持 `java` 、 `cshrp`和 `lua`; > * `-order` 模块顺序主文件,在-root之下的.order结尾文件;*可选*,默认为-root下的module.order文件。 > * `-order-include` 模块顺序追加文件,补充主文件内容;*可选*。由多个-root之下的.order文件名组成的参数,以半角逗号分割多个文件 > * `-pkg` 生成文件的包名(或者命名空间),*必须指定*,不需要可写 "" ``` e.g. java -Dfile.encoding=UTF-8 -jar net_protocol_builder.jar -lang java -root net_protocol -src src -gen gen/java/ -pkg "com.foo.bar.protocol.xxx" -order ``` ### 3.7 外部支持 * ptl文件(protocol template language) * 每个`message`定义一次消息传输,`struct`定义一个传输结构,`message`和`struct`是定义消息的基本单位; * 协议以消息作为通信结构定义单位,分为`server to client`和`client to server`,分别写在对应标题下; `struct`的定义是全局的,保证名称唯一; `message`的定义以文件(模块)划分,每个文件内保证名称唯一; `message`和`struct`的成员可使用几种基本类型作为数据类型,有: `int short long boolean byte float double string` 同时可以使用集合类型: `list set map` 还可以使用struct作为数据类型; `struct`/`message`中还可以嵌套`struct`作为数据类型,如 struct SomeNestedStruct { int a; long b; } struct OutterPOD { long myNum; SomeNestedStruct myPOD; } * 注释 可以使用//添加行注释 属性成员的描述以//开头跟在每个属性之后; `message`或`struct`的描述以//开头跟在定义首行之后; 如: struct SomeNestedStruct { // comment of nested struct int a;// comment of a long b; } * 继承 消息结构之间可以继承,在消息定义时通过关键字`:`实现 ## 批处理命令行 -root 指定当前运行工作目录,不指定即为当前目录,-src -gen等路径参数会以root为根目录 -lang 指定目标语言,现支持 `java`,`csharp`和`Lua`,参数分别为`java` `csharp` `lua` -src 协议描述文件目录(相对-root) -gen 源码输出目录(相对-root) -pkg 文件的根`package`(或`namespcae`);如`Java`中,`message`会存放在`%pkg%.message`下,`struct`会存放在`%pkg%.model`下; ## e.g. > java -Dfile.encoding=UTF-8 -jar net_protocol_builder.jar -lang java -root net_protocol -src src -gen gen/java/ -pkg "com.foo.bar.protocol.xxx" 语法、如何运行 ## 更新历史