【转】从零开始学习Skynet_examples研究

转自 http://blog.csdn.net/mr_virus/article/details/52330193

一、编译Skynet:

1、用ubuntu15.10直接

make linux

编译Skynet会有报错。安装autoconf、libreadline6、libreadline6-dev后就能编译成功了。

sudo apt-get install autoconf  

sudo apt-get install libreadline6 libreadline6-dev  


二、关于examples相关的代码分析:

1、关于examples/config里面有一行:

start = "main"  -- main script  

意思是通过start="main"开启第一个Skynet的服务main.lua。这个文件main.lua也在examples文件夹中:

local skynet = require "skynet"  
local sprotoloader = require "sprotoloader"  
  
local max_client = 64  
  
skynet.start(function()  
    skynet.error("Server start")  
    skynet.uniqueservice("protoloader")  
    if not skynet.getenv "daemon" then  
        local console = skynet.newservice("console")  
    end  
    skynet.newservice("debug_console",8000)  
    skynet.newservice("simpledb")  
    local watchdog = skynet.newservice("watchdog")  
    skynet.call(watchdog, "lua", "start", {  
        port = 8888,  
        maxclient = max_client,  
        nodelay = true,  
    })  
    skynet.error("Watchdog listen on", 8888)  
    skynet.exit()  
end)  

  

第一行先引用skynet这个库,这个库是用lua写的,即是lualib/skynet.lua。里面定义了这些接口:

 

1).skynet.start()用于服务的入口,加载lua服务时先运行这里的代码,它调用了luaclib-src/lua_skynet.c里面的callback(),最终调用skynet的框架skynet_callback()来设置毁掉函数。

2).skynet.newservice()用于启动一个lua写的服务,省略掉.lua后缀名。它调用了skynet.call()然后skynet.call()调用luaclib-src/lua_skynet.c里面send(),最终调用skynet的框架skynet_send()压入队列。

3).skynet.call()用于发送一条消息给Skynet的框架。消息会压入队列,等待SKynet框架的调度。

4).skynet.exit()移除服务,通过skynet.send()发送一条消息给skynet框架来移除lua的这个服务。

5).skynet.monitor()用于监视服务,看它是否关闭。

main.lua共打开了四个服务:

1).service_mgr:这个是系统的模块,用于管理服务。

2).console:这个是系统的模块,用于管理输出。

3).simpledb:这个是例子模块,用于管理Key-Value数据。

4).watchdog:这个是例子模块,用于监视socket端口,等待数据。

main.lua没有调用其他函数,加载完服务,它也就完成了任务,所以它最后调用了skynet.exit()把自己杀掉。

现在Skynet已经启动了watchdog服务,监听着8888端口,等待客户端的连接。

下面是watchdog服务的skynet_start()开始函数:

skynet.start(function()  
    skynet.dispatch("lua", function(session, source, cmd, subcmd, ...)  
        if cmd == "socket" then  
            local f = SOCKET[subcmd]  
            f(...)  
            -- socket api don't need return  
        else  
            local f = assert(CMD[cmd])  
            skynet.ret(skynet.pack(f(subcmd, ...)))  
        end  
    end)  
  
    gate = skynet.newservice("gate")  
end)

skynet.dispatch()这个服务的回调函数,通过SOCKET[]来调用函数,这些函数有:

 

SOCKET.open():打开agent服务并启动,使用gate来管理socket。

SOCKET.close():关闭agent服务。

SOCKET.error():打印错误信息。

SOCKET.data():有数据到来。
下面是agent服务代码:

function CMD.start(conf)  
    local fd = conf.client  
    local gate = conf.gate  
    WATCHDOG = conf.watchdog  
    -- slot 1,2 set at main.lua  
    host = sprotoloader.load(1):host "package"  
    send_request = host:attach(sprotoloader.load(2))  
    skynet.fork(function()  
        while true do  
            send_package(send_request "heartbeat")  
            skynet.sleep(500)  
        end  
    end)  

  client_fd = fd
  skynet.call(gate,"lua","forward",fd)
end
 
 
skynet.start(function()  
<span style="white-space:pre">    </span>skynet.dispatch("lua", function(_,_, command, ...)  
<span style="white-space:pre">        </span>local f = CMD[command]  
<span style="white-space:pre">        </span>skynet.ret(skynet.pack(f(...)))  
<span style="white-space:pre">    </span>end)  
end)  

前面watchdog调用SOCK.open()的时候就调用了这里的CMD.start(),在客户端输出了"Welcome to skynet"。

Agent的核心就是注册了协议,并根据协议把数据发送给simpledb服务去处理。

 
skynet.register_protocol {  
    name = "client",  
    id = skynet.PTYPE_CLIENT,  
    unpack = function (msg, sz)  
        return host:dispatch(msg, sz)  
    end,  
    dispatch = function (_, _, type, ...)  
        if type == "REQUEST" then  
            local ok, result  = pcall(request, ...)  
            if ok then  
                if result then  
                    send_package(result)  
                end  
            else  
                skynet.error(result)  
            end  
        else  
            assert(type == "RESPONSE")  
            error "This example doesn't support request client"  
        end  
    end  
}  

  

协议的详细部分看lualib/skynet.lua。

最后看看simpledb服务:

local skynet = require "skynet"  
require "skynet.manager"    -- import skynet.register  
local db = {}  
  
local command = {}  
  
function command.GET(key)  
    return db[key]  
end  
  
function command.SET(key, value)  
    local last = db[key]  
    db[key] = value  
    return last  
end  
  
skynet.start(function()  
    skynet.dispatch("lua", function(session, address, cmd, ...)  
        local f = command[string.upper(cmd)]  
        if f then  
            skynet.ret(skynet.pack(f(...)))  
        else  
            error(string.format("Unknown command %s", tostring(cmd)))  
        end  
    end)  
    skynet.register "SIMPLEDB"  
end)  

 

这里很简单地处理了SET和GET。

 

以上只是大概浏览了一遍Skynet附带的例子,了解了一些Skynet提供的lua接口,其他接口可以查看skynet.lua代码。

posted @ 2017-11-23 15:00  colourstar  阅读(1742)  评论(0编辑  收藏  举报