最近初次使用skynet开发项目,发现luaclib自定义库需要向lua的微服务及时推送消息,提高效率,大致参考了下skynet原有
代码,实现了消息推送功能.
luaclib中通过skynet_sendname接口向微服务推送消息时,需获取ctx,
service_snlua.c在初始化具体lua的微服务时,会在lua注册表中设置ctx,现有框架中已实现 ,代码如下
static int
init_cb(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) {
lua_State *L = l->L;
l->ctx = ctx;
lua_gc(L, LUA_GCSTOP, 0);
lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
luaL_openlibs(L);
lua_pushlightuserdata(L, ctx);
lua_setfield(L, LUA_REGISTRYINDEX, "skynet_context");
luaL_requiref(L, "skynet.codecache", codecache , 0);
lua_pop(L,1);
...
}
既然lua注册表中已存放ctx,考虑文本JSON字符串方式推送:
skynet_sendname(pctx, 0, “.luasvrname”, PTYPE_TEXT, 0, szJson, strlen(szJson));
服务lua代码如下:
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
unpack = skynet.tostring,
dispatch = function(session, address , cmd)
--具体消息处理
end,
}
那么ctx如何获取呢,我们可以参考skynet中现有的luaclib库中的代码,如:lua-sock.c lua-skynet.c
LUAMOD_API int
luaopen_skynet_core(lua_State *L) {
...
// 从lua注册表中获取当前服务的ctx,并同时放到栈顶
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");
}
// 下方注册函数方法中的最后一个参数, 1表示将栈中的一个参数设置为upvalue,然后在此库中, 可通过
// struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
// 方法获取ctx,具何还可参考:云风 第八章 内置库的实现 的说明
luaL_setfuncs(L,l,1);
return 1;
}
最终lua参考如下:
local skynet = require "skynet"
local json = require "json"
local testhandler = require "test"
require "skynet.manager"
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
unpack = skynet.tostring,
dispatch = function(session, address , cmd)
-- 具体消息处理
end,
}
skynet.start(function()
testhandler.init()
skynet.dispatch("lua", function(session, address, cmd, jValue)
end)
skynet.register ".testcb"
end)
最终luaclib库的C代码参考如下:
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "skynet.h"
}
#endif
struct skynet_context * g_context = NULL;
void* thread(void *param)
{
int i = 0;
while (true)
{
char szValue[1024] = { 0 };
sprintf(szValue, "{ \"method\":\"test\", \"params\": { \"id\":%d} }", i++);
skynet_sendname(g_context, 0, ".testcb", PTYPE_TEXT, 0, szValue, strlen(szValue));
usleep(1000*100);
}
return NULL;
}
int linit(lua_State *L)
{
g_context = (struct skynet_context *)lua_touserdata(L, lua_upvalueindex(1));
pthread_t ThreadID;
pthread_create(&ThreadID, NULL, thread, NULL);
return 0;
}
LUAMOD_API int
luaopen_test(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "init", linit },
{ NULL, NULL },
};
luaL_newlibtable(L, l);
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");
struct skynet_context *ctx = (struct skynet_context*)lua_touserdata(L, -1);
if (ctx == NULL) {
return luaL_error(L, "Init skynet context first");
}
luaL_setfuncs(L, l, 1);
return 1;
}