🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 概述 引用云风博客的话:"skynet 是一个为网络游戏服务器设计的轻量框架。但它本身并没有任何为网络游戏业务而特别设计的部分,所以尽可以把它用于其它领域。skynet 并不是一个开箱即用的引擎,使用它需要先对框架本身的结构有所了解,理解框架到底帮助开发者解决怎样的问题。如果你希望使用这个框架来开发网络游戏服务器,你将发现,skynet 并不会引导你把服务器搭建起来。它更像是一套工具,只有你知道你想做什么,它才会帮助你更有效率的完成。" 详情请参考:https://github.com/cloudwu/skynet/wiki/GettingStarted ## 下载 & 编译 安装环境: * ubuntu16.04 * gcc5.4 * make 从[github](https://github.com/cloudwu/skynet)上下载 ```shell $ git clone https://github.com.cnpmjs.org/cloudwu/skynet.git $ cd skynet && make linux ``` ## 解析示例 启动一个服务端和客户端示例: ```shell ./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`服务的脚本 ```lua -- 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脚本 ```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 -- 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.start`、`skynet.dispatch`、`skynet.register`、skynet.call、skynet.newservice这几个重要的方法 ## 改造成C/S架构的echo 了解了一下skynet的网络模型是actor模型,这样写起服务来更加得心应手了。 一个`echo_server.lua` 监听服务 ```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` ```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` ```config 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" ``` 启动 ```shell ./skynet examples/config.echo ``` 附上一个客户端测试一下服务器 ```lua 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://github.com/liuhaopen/SkynetMMO https://github.com/cloudwu/skynet/wiki/GettingStarted