看好项目的源码总是会有重复造轮子的冲动。最近对比测了下我们业务使用的数据序列化协议的性能,review了社区上几个常用库的源码,尝试做了点优化,有些想法。浅浅写了个demo,这里记录下实现的思路,供后面查阅和反思。
协议的实现分为几个部分:
schema text:协议描述文件
compiler :解析器,负责将描述文件解析成FIX驱动层语言类型的协议配置
driver:驱动层,维护编译器生成的协议配置,具备查询、编码解码以及热更新等能力
adapter:适配器,提供多种编程语言链接驱动层的API
- 协议描述文件(schema text)
# TAG:
# @TYPE:struct definition
# @RPC:rpc definition
TYPE 1001 tinyuser [[
int id = 0
str name = 1
bool online = 3
list friend = 4
]]
RPC 1001 svr_view_tinyuser [[
request [[
int id = 0
]]
response [[
# allow nesting
TYPE 1 ret [[
bool ok = 0
str msg = 1
]]
type ret result = 0 # use keyword `type` when field is not built in
type tinyuser user = 1
]]
]]
协议格式支持:
1)通用数据格式类型;
2)自定义结构体类型;
3)结构体类型嵌套;
4)请求回应模式的定义(将请求和回应看成是单独的自定义类型)
- 解析器(compiler)
解析器将描述文件解析为兼容驱动层语言的配置内容(以lua为例):
local types = {
[1001] = {
name = "tinyuser",
tag = 1001,
fields = {
{ name = "id", tag = 0, tp = SERIALIZE_TYPE_INT, buildin = true },
{ name = "name", tag = 1, tp = SERIALIZE_TYPE_STR, buildin = true },
{ name = "online", tag = 2, tp = SERIALIZE_TYPE_BOOL, buildin = true },
{ name = "friend", tag = 3, tp = SERIALIZE_TYPE_LIST, buildin = true }
}
},
[1001.1] = {
name = "svr_view_tinyuser.request",
tag = 1001.1,
fields = {
{ name = "id", tag = 0, tp = SERIALIZE_TYPE_INT, buildin = true }
}
},
[1001.2.1] = {
name = "svr_view_tinyuser.response.ret",
tag = 1001.2.1,
fields = {
{ name = "ok", tag = 0, tp = SERIALIZE_TYPE_BOOL, buildin = true },
{ name = "msg", tag = 1, tp = SERIALIZE_TYPE_STR, buildin = true },
}
},
[1001.2] = {
name = "svr_view_tinyuser.response",
tag = 1001.2,
fields = {
{ name = "result", tag = 0, tp = "svr_view_tinyuser.response.ret", buildin = false },
{ name = "player", tag = 1, tp = "tinyuser", buildin = false }
}
},
}
local protocols = {
[1001] = {
name = "svr_view_tinyuser",
tag = 1001,
nesting = true
}
}
local group = { types, protocols }
解析器提供两种结果获取方式:1. API实时获取 2. 生成解析文件(支持加密)
function compiler.dumpproto(fname)
fname = string.format("%s.pb", fname)
dump2file(fname, group)
end
function compiler.getproto()
return group
end
解析器提供解析文件的加载(解密)接口
function compiler.loadbin(bin)
-- ... decryption
return proto
end
function compiler.loadproto(pbfile)
pbfile = string.format("%s.pb", pbfile)
local f = assert(io.open(pbfile), "Can't open " .. pbfile)
local bin = f:read("a")
f:close()
return compiler.loadbin(bin)
end
- 驱动层(driver)
驱动层用于维护和驱动协议解析配置相关的信息:
local compiler = require("complier")
local host = {}
local function loadproto(schematext)
local proto = compiler.loadproto(schematext)
return setmetatable({_proto = proto}, {__index = host})
end
function host:queryproto(protocol)
-- search in proto.protocols
end
function host:querytype(tpname)
-- search in proto.types
end
local serializefuncs = { --[[ SERIALIZE_TYPE = opfunc --]] }
local unserializefuncs = { --[[ SERIALIZE_TYPE = opfunc --]] }
function host:encodeproto(tpname, data)
-- ... encode lua table to bin by proto formation
return bins
end
function host:decodeproto(tpname, msg)
-- decode bin msg to lua by proto formation
return result
end
local driver = {
loadproto = loadproto,
-- ...
}
local rpc = {
send = function(sp, rpc_name, data)
local typename = string.format("%s.request", rpc_name)
return sp:encodeproto(typename, data)
end,
recv = function(sp, rpc_name, msg)
local typename = string.format("%s.request", rpc_name)
return sp:decodeproto(typename, msg)
end,
retsend = function(sp, rpc_name, retdata)
local typename = string.format("%s.response", rpc_name)
return sp:encodeproto(typename, retdata)
end,
retrecv = function(sp, rpc_name, retmsg)
local typename = string.format("%s.response", rpc_name)
return sp:decodeproto(typename, retmsg)
end
}
- 适配器(adapter)
import lupa
lua = lupa.LuaRuntime()
# load comoiler
lua.execute(loadfile(compiler))
compiler_core, compiler_rpc = lua.globals.core, lua.globals.rpc
class Adapter:
def __init__(self, compiler_core, compiler_rpc, schematext):
self._ccompiler_core = compiler_core
self._compiler_rpc = compiler_rpc
self.proto = self._compiler_core.loadproto(schematext)
def rpc_send():
self._compiler_rpc.send()
# ...
标签:function,protocol,name,demo,rpc,tag,local,compiler
From: https://www.cnblogs.com/linxx-/p/18216818