Skynet使用之:c-lua接口和so动态库

JavenLaw

Skynet中的例子

c-lua的接口是比较重要的一部分

因为skynet底层使用的c语言,上层使用lua来实现,必然关涉到c-lua的交互

我们重点关注:skynet/lualib-src目录下的文件

在平时分析Skynet源码的时候,我们经常可以看到类似的调用

local c = require "skynet.core"

-- 这里的skynet就是在 skynet/lualib-src/lua-skynet.c 文件下实现的
-- 只不过是 skynet/lualib-src 文件下的c文件,最终都被编译到 skynet/luaclib 下
-- 详细见《Skynet源码准备》

在skynet/lualib/skynet.lua中

local c = require "skynet.core"

-- 除了一些普通的API调用
c.send()
c.error()

-- skynet还封装了一些常用的命令
-- 但是通过统一的接口来使用
c.intcommand("STAT", "mqlen")
c.command("EXIT")

-- 以上命令就能直接在lua层调用c层的函数
-- 当然这种形式最后得需要c文件编译为so库才行

而在skynet/lualib-src/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层的函数调用,在c层都有一一对应的c函数实现

最终完成了c-lua的交互

其实:zlog的c-lua调用和skynet的c-lua调用也是一样的

详细见在zlog的编译脚本和文件


实际举例

//make so lib for lua.
//cc -g -O2 -Wall -fPIC --shared usertime.c -o usertime.so

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <lua.h>
#include <lauxlib.h>

//微秒
static int getmicrosecond(lua_State *L) {
  struct timeval tv;
  gettimeofday(&tv,NULL);
  long microsecond = tv.tv_sec*1000000+tv.tv_usec;
  lua_pushnumber(L, microsecond);
  return 1;
}

//毫秒
static int getmillisecond(lua_State *L) {
  struct timeval tv;
  gettimeofday(&tv,NULL);
  long millisecond = (tv.tv_sec*1000000+tv.tv_usec)/1000;
  lua_pushnumber(L, millisecond);

  return 1;
}

int luaopen_usertime(lua_State *L) {
  luaL_checkversion(L);

  luaL_Reg l[] = {
    {"getmillisecond", getmillisecond},
    {"getmicrosecond", getmicrosecond},
    { NULL, NULL },
  };

  luaL_newlib(L, l);

  return 1;
}

这个文件即可以编译出一个usertime.so,放入lua的搜索路径下

在直接require “usertime”,即可以直接使用对应的函数了


参考资料

如何在 skynet 中加入 C 库 · cloudwu/skynet Wiki (github.com)

skynet/CJSON.md at cjson · hanxi/skynet (github.com)

lua调用c函数 · cloudwu/skynet · Discussion #1681 (github.com)