概述

引用云风博客的话:“skynet 是一个为网络游戏服务器设计的轻量框架。但它本身并没有任何为网络游戏业务而特别设计的部分,所以尽可以把它用于其它领域。skynet 并不是一个开箱即用的引擎,使用它需要先对框架本身的结构有所了解,理解框架到底帮助开发者解决怎样的问题。如果你希望使用这个框架来开发网络游戏服务器,你将发现,skynet 并不会引导你把服务器搭建起来。它更像是一套工具,只有你知道你想做什么,它才会帮助你更有效率的完成。”
详情请参考:https://github.com/cloudwu/skynet/wiki/GettingStarted

下载 & 编译

安装环境:

  • ubuntu16.04
  • gcc5.4
  • make 从github上下载
$ git clone https://github.com.cnpmjs.org/cloudwu/skynet.git 
$ cd skynet && make linux

解析示例

启动一个服务端和客户端示例:

./skynet examples/config	# Launch first skynet node  (Gate server) and a skynet-master (see config for standalone option)
./3rd/lua/lua examples/client.lua 	# Launch a client, and try to input hello.

我是一个skynet小白,在我第一次看到官方示例的时候,只能看懂语法,但是不知道其中的逻辑关系。根据以往学习项目的经验,我先研究的怎么使用,然后再看源代码。在网上找到这个教程:https://blog.csdn.net/119365374/article/details/77790653, 写一个echo,可以很好的理解skynet的使用。 写echo服务的脚本

-- echo.lua
local skynet = require("skynet")
require ("skynet.manager")

local  command  = {<!-- -->}

function command.HELLO(what)
    return "I am echo server: ".. what
end

skynet.start(function()
    skynet.dispatch("lua", function(session, address, cmd, ...)
        cmd = cmd:upper()
        if cmd == "HELLO" then
            local f = command[cmd]
            assert(f)
            skynet.ret(skynet.pack(f(...)))
        end
    end)
    -- skynet.register("echo")  --这句可以不要,已经验证过
end)

skynet.dispatch("lua", function(session, address, cmd, ...) end)三个参数解释

  • sesson: 请求序列号,是一个自增的id,溢出了又从1开始
  • address:是skynet中服务的地址,这个地址在运行时是唯一的。在上面的代码中就是代表echo服务自已的地址。它实际上也是一个数字。
  • cmd: 请求命令

调用echo服务的test_echo.lua脚本

-- test_echo.lua
local skynet = require "skynet"

skynet.start(function ()
    local echo = skynet.newservice("echo")
    print(skynet.call(echo, "lua", "HELLO", "WORLD"))
end)

调用函数skynet.call(echo, "lua", "HELLO", "WORLD")中四个参数的解释,

  • echo: 调用服务的地址,与上面的address对应;
  • HELLO: 请求命令,与上面的cmd对应;
  • WORLD:请求参数;
  • call是阻塞式调用。

写配置文件 examples/config.echo

-- config.echo
include "config.path"
-- preload = "./examples/preload.lua"	-- run preload.lua before every lua service run
thread = 8
logger = nil
logpath = "."
harbor = 1
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "test_echo"	--  指定启动的脚本名字
bootstrap = "snlua bootstrap"	-- The service for bootstrap
standalone = "0.0.0.0:2013"
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

运行:

$ ./skynet examples/config.echo

这个例子让我们学习了skynet.startskynet.dispatchskynet.register、skynet.call、skynet.newservice这几个重要的方法

改造成C/S架构的echo

了解了一下skynet的网络模型是actor模型,这样写起服务来更加得心应手了。
一个echo_server.lua 监听服务

local skynet = require "skynet"
local socket = require("skynet.socket")
local echo

function accept(id, addr)
    print("accept connect from addr: "..  addr .. "; id: ".. id)
    print(skynet.call(echo, "lua", "RWING", id))
end

skynet.start(function()
    -- 读写的服务
    echo = skynet.newservice("echo_rw")
    -- 监听8883端口
    local listen_id = socket.listen("0.0.0.0", 8883)
    -- 开始监听
    socket.start(listen_id, accept)
end)

读写服务 echo_rw.lua

local skynet = require("skynet")
local socket = require("skynet.socket")
require ("skynet.manager")

local  command  = {<!-- -->}

-- 这个函数才是 echo函数 接收客户端的数据,并且把数据原封不动的发回给客户端
function command.RWING(id)
    print("start id: " .. id)
    socket.start(id)
    while true do
        --  读取客户端的数据
        local msg = socket.read(id, nil)
        if msg then
            print("recv msg: ".. msg)
            socket.write(id, msg)
        else
            socket.close(id)
            return
        end

    end
end

skynet.start(function()
    skynet.dispatch("lua", function(session, address, cmd, ...)
        cmd = cmd:upper()
        if cmd == "RWING" then
            local f = command[cmd]
            assert(f)
            skynet.ret(skynet.pack(f(...)))  --这个是模仿skynet例子里写的
        end
    end)
    skynet.register("echo_rw")
end)

配置文件 config.echo

include "config.path"

-- preload = "./examples/preload.lua"	-- run preload.lua before every lua service run
thread = 8
logger = nil
logpath = "."
harbor = 1
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "echo_server"	-- echo_server script 主要是改 脚本名字
bootstrap = "snlua bootstrap"	-- The service for bootstrap
standalone = "0.0.0.0:2013"
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

启动

./skynet examples/config.echo

附上一个客户端测试一下服务器

package.cpath = "luaclib/?.so"
package.path = "lualib/?.lua;examples/?.lua"

if _VERSION ~= "Lua 5.4" then
	error "Use lua 5.4"
end

local socket = require("client.socket")
local fd = assert(socket.connect("127.0.0.1", 8883))

local function sendpkg(fd, pack)
    local package = string.pack(">s2", pack)
    print("send msg: " .. package)
	socket.send(fd, package)
end

local function recvpkg(fd)
    local msg = socket.recv(fd)
    if not msg then
        return
    end
    if msg == "" then
        return
    end
    print("recv from server msg: " .. msg)
end

function main()
    sendpkg(fd, "hello world I'm Allen!!!")  --发送消息
    while true do   
        recvpkg(fd) --接收消息写在循环里
    end
end

main()

这是我入门skynet框架写的一个小demo,到这里就结束了,希望能对刚接触skynet的同学有所帮助。对了,skynet是使用actor作为通信模型,了解了actor之后可以更好的理解skynet。

参考连接:https://blog.csdn.net/119365374/article/details/77790653

--完--