在一個稍微複雜的系統中會涉及到多語言編程,例如:後端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。其他的語言類似,也可以根據項目中使用的語言修改協議翻譯器,讓它支持你所用的語言。
def協議接口介紹
基礎數據類型:
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框架的主要特性之一。