在一个稍微复杂的系统中会涉及到多语言编程,例如:后端C++和JAVA,脚本用LUA,前端可能是C++ AS等等。所以所有模块之间的协议统一变得非常重要,这样做的目的是减少中间的调试和差错。在revolver框架中,实现了一个基于简单的接口语言来实现多语言之间接口协议的实现。所有的协议接口通过一个简单的def文件就可以将协议翻译成对应的语言程序代码,这样尽可能的避免中间环节的差错,也大大提高了编码效率。而且revolver使用的是标准网络字节序描述协议报文数据,所以可以在各种系统下使用各种语言进行混合编程。
以下是一个revolver的sample_msg.def事例接口程序文档:
#生成的文件名
filetitle = sample_msg
#命名空间
namespace = BASE
#ip地址类型声明
datatype(Inet_Addr)
#数组定义
typedef array<int8> : INT8_ARRAY
typedef array<int32> : INT32_ARRAY
#二进制数据
typedef string : BIN_DATA
#结构体定义
datatype(CDesc)
{
int8 n_type = 0
string str_desc = ""
INT32_ARRAY arr_fd
INT8_ARRAY arr_status
}
#协议消息ID定义
var SAMPLE_MSGID = 0xff000001
#协议体和消息关联定义
message(CSamplePacket, SAMPLE_MSGID)
{
uint8 msg_type = 0
uint16 seq_id = 0
uint32 user_id = 0
uint64 guid = 0
Inet_Addr server_addr
BIN_DATA bin_data
CDesc msg_desc
}
以上是基本的def定义,如果要将协议翻译成c++框架能认识的协议,就需要通过revolver中提供的协议翻译器来进行翻译,协议翻译器在revolver项目中protocol_analysis工程编译得到,会生成一个make.exe。生成make程序后,可在命令行里输入make sample_msg.def c++,就可生成对应的C++接口协议。生成的C++接口文件如下:
namespace BASE { #define SAMPLE_MSGID 0xff000001 typedef string BIN_DATA; typedef vector<int32_t> INT32_ARRAY; typedef vector<int8_t> INT8_ARRAY; class CDesc { public: CDesc() { n_type = 0; str_desc = ""; } ~CDesc() { } public: int8_t n_type; string str_desc; INT32_ARRAY arr_fd; INT8_ARRAY arr_status; friend BinStream& operator<<(BinStream& strm, const CDesc& packet) { strm << packet.n_type; strm << packet.str_desc; int32_t count_0 = packet.arr_fd.size(); strm << count_0; for (int32_t i = 0; i < count_0; i++) { strm << packet.arr_fd[i]; } int32_t count_1 = packet.arr_status.size(); strm << count_1; for (int32_t i = 0; i < count_1; i++) { strm << packet.arr_status[i]; } return strm; } friend BinStream& operator>>(BinStream& strm, CDesc& packet) { strm >> packet.n_type; strm >> packet.str_desc; int32_t count_2 = 0; strm >> count_2; packet.arr_fd.resize(count_2); for (int32_t i = 0; i < count_2; i++) { strm >> packet.arr_fd[i]; } int32_t count_3 = 0; strm >> count_3; packet.arr_status.resize(count_3); for (int32_t i = 0; i < count_3; i++) { strm >> packet.arr_status[i]; } return strm; } void Print(std::ostream& os) const { os << "CDesc, {"; os << "n_type = " << (int16_t)n_type << ","; os << "str_desc = " << str_desc << ","; os << "arr_fd = "; for (uint32_t i = 0; i < arr_fd.size(); i++) { os << arr_fd[i] << ","; } os << "arr_status = "; for (uint32_t i = 0; i < arr_status.size(); i++) { os << (int16_t)arr_status[i] << ","; } os << "}"; } friend ostream& operator<<(ostream& os, const CDesc& packet) { packet.Print(os); return os; } }; class CSamplePacket : public CBasePacket { public: CSamplePacket() { msg_type = 0; seq_id = 0; user_id = 0; guid = 0; } ~CSamplePacket() { } public: uint8_t msg_type; uint16_t seq_id; uint32_t user_id; uint64_t guid; Inet_Addr server_addr; BIN_DATA bin_data; CDesc msg_desc; public: void Pack(BinStream& strm) const { strm << msg_type; strm << seq_id; strm << user_id; strm << guid; strm << server_addr; strm << bin_data; strm << msg_desc; } void UnPack(BinStream& strm) { strm >> msg_type; strm >> seq_id; strm >> user_id; strm >> guid; strm >> server_addr; strm >> bin_data; strm >> msg_desc; } void Print(std::ostream& os) const { os << "CSamplePacket, {"; os << "msg_type = " << (uint16_t)msg_type << ","; os << "seq_id = " << seq_id << ","; os << "user_id = " << user_id << ","; os << "guid = " << guid << ","; os << "server_addr = " << server_addr << ","; os << "bin_data's size = " << bin_data.size(); os << "msg_desc = " << msg_desc << ","; os << "}"; } };也可以生成lua 或者AS 等。命令make sample_msg.def lua 或者make sample_msg.def as。其他的语言类似,也可以根据项目中使用的语言修改协议翻译器,让它支持你所用的语言。
基础数据类型:
int8 有符号单字节整型数
uint8 无符号单字节整型数
int16 有符号双字节整型数
uint16 无符号双字节整型数
int32 有符号4字节整型数
uint32 无符号4字节整型数
int64 有符号8字节整型数
uint64 无符号8字节整型数
string 字符串
BIN_DATA 二进制数组
Inet_Addr IP v4地址,包括端口
关键字:
var 数字定义关键字
array 数组关键字
datatype 数据结构定义关键字,类似结构体
message 协议定义关键字
typedef 重定义关键字
{ 结构的开始
} 结构的结束
# 注释关键字
revolver提供协议接口编程,就是将自动化引入整个框架,减少因为协议带来的调试和差错,重在提高生产效率。这也是revolver框架的主要特性之一。