skynet luaclib库主动推送消息至服务方法

skynet luaclib库主动推送消息至服务方法

最近初次使用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;
}

你可能感兴趣的:(skynet)