SuperSheeps常见RPC协议解析

1. Websocket 和 Http

--这部分代码用于网络消息的解析和封包
local http = require "http_plugin.http"
local ws = require 'http_plugin.websocket'

--websocket握手阶段,使用http协议

--解析用例消息
local ret, req = http.request_decode(data)
--打包协议,将协议序列化为二进制
local data = http.request_encode(req)
--解析服务器消息,此处不掩饰粘包处理
local ret, res = http.response_decode(data)

--握手完成,使用websocket协议

--解析用例或者服务器消息,此处不演示粘包处理
local content, fin, opcode, encoded_bak, mask, len = ws.decode(data)
--打包协议,将协议序列化为二进制
local data = ws.encode(content, opcode, mask, fin)

2. Json

local json = require "JSON"

--解析用例或者服务器消息
local obj = json:decode(data)
--打包协议,将协议序列化为二进制
local str = json:encode(obj)

3. Sproto

sproto是云风设计一种rpc协议:https://github.com/cloudwu/sproto

--sheeps.lua
--这部分代码加载协议文件,sheeps.lua是框架默认的一个lua虚拟机初始化脚本
local sprotoloader = require "sprotoloader"

function global_vm_init(projectid)
  sprotoloader.register("project/lua/"..projectid.."/proto/C2S.proto", 1)
  sprotoloader.register("project/lua/"..projectid.."/proto/S2C.proto", 2)
end

function user_vm_init(projectid)
  local SP_C2S = sprotoloader.load(1)
  local SP_S2C = sprotoloader.load(2)
  C2SHost = SP_C2S:host("Package")
  S2CHost = SP_S2C:host("Package")
  C2SRequest = S2CHost:attach(SP_C2S)
end
--这部分代码用于网络消息的解析和封包

--解析用例消息,此处不演示粘包处理
local ok, rpctype, name, request, response, ud = pcall(C2SHost.dispatch, C2SHost, data)
--打包协议,将协议序列化为二进制
local data = C2SRequest(name, request, session, ud)
--解析服务器消息,此处不掩饰粘包处理
local ok, rpcType, name, request, response, ud = pcall(S2CHost.dispatch, S2CHost, data)

4. Protobuf

supersheeps 内置luaprotobuf库:https://github.com/starwing/lua-protobuf

//定义addressbook.proto文件
package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
  required string name = 1;
  required int32 uid = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
  repeated int32 test = 5 [packed=true];

  extensions 10 to max; 
}

message Ext {
  extend Person {
    optional int32 test = 10;
  }
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person person = 1;
}

使用命名 protoc -o addressbook.pb addressbook.proto 生成 addressbook.pb,然后:

assert(pb.loadfile "addressbook.pb") -- 载入刚才编译的pb文件

local person = { -- 我们定义一个addressbook里的 Person 消息
   name = "Alice",
   id = 12345,
   phone = {
      { number = "1301234567" },
      { number = "87654321", type = "WORK" },
   }
}

-- 序列化成二进制数据
local data = assert(pb.encode("tutorial.Person", person))

-- 从二进制数据解析出实际消息
local msg = assert(pb.decode("tutorial.Person", data))

5. KCP

supersheeps内置KCP协议的支持,但是使用kcp的项目通过socks5代理录制的用例消息种会带有kcp协议头,在业务层需要去除。了解KCP:https://github.com/skywind3000/kcp

--解析kcp用例消息
local KcpSn = -1
local function KcpSendMsgUnpack(data)
	-- kcp协议头24个字节,判断长度是否足够
	local data_len = #data
    if data_len < 24 then
        return
    end
    local pos = 1
    local len = 0
    while pos < data_len do
        local sn, npos = string.unpack("I", data, pos + 12)
        len, pos = string.unpack("I", data, pos + 20)
		--通过 len > 0 过滤控制帧, 通过 sn > KcpSn 过滤重发的帧
        if len > 0 and sn > KcpSn then
            KcpSn = sn
			--conent为业务层需要的数据
            local content = string.sub(data, pos, pos + len - 1)
        end
        pos = pos + len
    end
end

SuperSheeps常见RPC协议解析