skynet.pack与skynet.unpack实现分析
skynet.lua
358行 可以看到如下定义
skynet.pack = assert(c.pack)
skynet.packstring = assert(c.packstring)
skynet.unpack = assert(c.unpack)
skynet.tostring = assert(c.tostring)
skynet.trash = assert(c.trash)
local c = require "skynet.core"
可以知道这是c实现的 找到文件 lua-skynet.c
LUAMOD_API int
luaopen_skynet_core(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{
"send" , lsend },
{
"genid", lgenid },
{
"redirect", lredirect },
{
"command" , lcommand },
{
"intcommand", lintcommand },
{
"addresscommand", laddresscommand },
{
"error", lerror },
{
"harbor", lharbor },
{
"callback", lcallback },
{
"trace", ltrace },
{
NULL, NULL },
};
// functions without skynet_context
luaL_Reg l2[] = {
{
"tostring", ltostring },
{
"pack", luaseri_pack },
{
"unpack", luaseri_unpack },
{
"packstring", lpackstring },
{
"trash" , ltrash },
{
"now", lnow },
{
"hpc", lhpc }, // getHPCounter
{
NULL, NULL },
};
lua_createtable(L, 0, sizeof(l)/sizeof(l[0]) + sizeof(l2)/sizeof(l2[0]) -2);
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");
struct skynet_context *ctx = lua_touserdata(L,-1);
if (ctx == NULL) {
return luaL_error(L, "Init skynet context first");
}
luaL_setfuncs(L,l,1);
luaL_setfuncs(L,l2,0);
return 1;
}
可以看到pack、unpack都在这里
luaseri_pack 的实现在 lua-seri.lua文件中
//一个链表
struct block {
struct block * next;
char buffer[BLOCK_SIZE];
};
struct write_block {
struct block * head;
struct block * current;
int len;
int ptr;
};
LUAMOD_API int
luaseri_pack(lua_State *L) {
struct block temp;
temp.next = NULL;
struct write_block wb;
wb_init(&wb, &temp);
pack_from(L,&wb,0);
assert(wb.head == &temp);
seri(L, &temp, wb.len);
wb_free(&wb);
return 2;
}
//做一些初始化的工作
static void
wb_init(struct write_block *wb , struct block *b) {
wb->head = b;
assert(b->next == NULL);
wb->len = 0;
wb->current = wb->head;
wb->ptr = 0;
}
//打包数据
static void
pack_from(lua_State *L, struct write_block *b, int from) {
//lua_gettop(L) 获取栈的大小
int n = lua_gettop(L) - from; //n 为整个栈的大小
int i;
for (i=1;i<=n;i++) {
pack_one(L, b , from + i, 0);
}
}
//一个一个打包
//#define MAX_DEPTH 32
static void
pack_one(lua_State *L, struct write_block *b, int index, int depth) {
if (depth > MAX_DEPTH) {
//depth在这里始终为0
wb_free(b);
luaL_error(L, "serialize can't pack too depth table");
}
int type = lua_type(L,index); //获取数据类型
switch(type) {
case LUA_TNIL:
wb_nil(b);
break;
case LUA_TNUMBER: {
if (lua_isinteger(L, index)) {
//int类型
lua_Integer x = lua_tointeger(L,index);
wb_integer(b, x);
} else {
lua_Number n = lua_tonumber(L,index);
wb_real(b,n);
}
break;
}
case LUA_TBOOLEAN:
wb_boolean(b, lua_toboolean(L,index));
break;
case LUA_TSTRING: {
size_t sz = 0;
const char *str = lua_tolstring(L,index,&sz);
wb_string(b, str, (int)sz);
break;
}
case LUA_TLIGHTUSERDATA:
wb_pointer(b, lua_touserdata(L,index));
break;
case LUA_TTABLE: {
if (index < 0) {
index = lua_gettop(L) + index + 1;
}
wb_table(L, b, index, depth+1);
break;
}
default:
wb_free(b);
luaL_error(L, "Unsupport type %s to serialize", lua_typename(L, type));
}
}
#define TYPE_NIL 0
#define TYPE_BOOLEAN 1
// hibits 0 false 1 true
#define TYPE_NUMBER 2
// hibits 0 : 0 , 1: byte, 2:word, 4: dword, 6: qword, 8 : double
#define TYPE_NUMBER_ZERO 0
#define TYPE_NUMBER_BYTE 1
#define TYPE_NUMBER_WORD 2
#define TYPE_NUMBER_DWORD 4
#define TYPE_NUMBER_QWORD 6
#define TYPE_NUMBER_REAL 8
#define TYPE_USERDATA 3
#define TYPE_SHORT_STRING 4
// hibits 0~31 : len
#define TYPE_LONG_STRING 5
#define TYPE_TABLE 6
#define COMBINE_TYPE(t,v) ((t) | (v) << 3) //用一个字节表示类型和长度
#define BLOCK_SIZE 128
#define MAX_DEPTH 32
static inline void
wb_integer(struct write_block *wb, lua_Integer v) {
int type = TYPE_NUMBER;
if (v == 0) {
uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_ZERO); // (10) | (0000) = 00000010
wb_push(wb, &n, 1); //占用一个字节
} else if (v != (int32_t)v) {
uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_QWORD); // (10) | (110000) = 00110010
int64_t v64 = v;
wb_push(wb, &n, 1);
wb_push(wb, &v64, sizeof(v64)); //占用九个字节
} else if (v < 0) {
int32_t v32 = (int32_t)v;
uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_DWORD);
wb_push(wb, &n, 1);
wb_push(wb, &v32, sizeof(v32)); //占用5个字节
} else if (v<0x100) {
uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_BYTE);
wb_push(wb, &n, 1);
uint8_t byte = (uint8_t)v;
wb_push(wb, &byte, sizeof(byte));
} else if (v<0x10000) {
uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_WORD);
wb_push(wb, &n, 1);
uint16_t word = (uint16_t)v;
wb_push(wb, &word, sizeof(word));
} else {
uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_DWORD);
wb_push(wb, &n, 1);
uint32_t v32 = (uint32_t)v;
wb_push(wb, &v32, sizeof(v32));
}
}
unpack
//解包
int
luaseri_unpack(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
void * buffer;
int len;
if (lua_type(L,1) == LUA_TSTRING) {
size_t sz;
buffer = (void *)lua_tolstring(L,1,&sz);
len = (int)sz;
} else {
buffer = lua_touserdata(L,1);
len = luaL_checkinteger(L,2);
}
if (len == 0) {
return 0;
}
if (buffer == NULL) {
return luaL_error(L, "deserialize null pointer");
}
lua_settop(L,1);
struct read_block rb;
rball_init(&rb, buffer, len);
int i;
for (i=0;;i++) {
if (i%8==7) {
luaL_checkstack(L,LUA_MINSTACK,NULL);
}
uint8_t type = 0;
uint8_t *t = rb_read(&rb, sizeof(type));
if (t==NULL)
break;
type = *t;
push_value(L, &rb, type & 0x7, type>>3);
}
// Need not free buffer
return lua_gettop(L) - 1;
}
//先读取一个字节 获取类型与大小
static void *
rb_read(struct read_block *rb, int sz) {
if (rb->len < sz) {
return NULL;
}
int ptr = rb->ptr;
rb->ptr += sz;
rb->len -= sz;
return rb->buffer + ptr;
}
//TYPE_NUMBER_ZERO 00000010 type & 0x7 = 10 = 2 type>>3 = 0
static void
push_value(lua_State *L, struct read_block *rb, int type, int cookie) {
switch(type) {
case TYPE_NIL:
lua_pushnil(L);
break;
case TYPE_BOOLEAN:
lua_pushboolean(L,cookie);
break;
case TYPE_NUMBER:
if (cookie == TYPE_NUMBER_REAL) {
lua_pushnumber(L,get_real(L,rb));
} else {
lua_pushinteger(L, get_integer(L, rb, cookie));
}
break;
case TYPE_USERDATA:
lua_pushlightuserdata(L,get_pointer(L,rb));
break;
case TYPE_SHORT_STRING:
get_buffer(L,rb,cookie);
break;
case TYPE_LONG_STRING: {
if (cookie == 2) {
uint16_t *plen = rb_read(rb, 2);
if (plen == NULL) {
invalid_stream(L,rb);
}
uint16_t n;
memcpy(&n, plen, sizeof(n));
get_buffer(L,rb,n);
} else {
if (cookie != 4) {
invalid_stream(L,rb);
}
uint32_t *plen = rb_read(rb, 4);
if (plen == NULL) {
invalid_stream(L,rb);
}
uint32_t n;
memcpy(&n, plen, sizeof(n));
get_buffer(L,rb,n);
}
break;
}
case TYPE_TABLE: {
unpack_table(L,rb,cookie);
break;
}
default: {
invalid_stream(L,rb);
break;
}
}
}