skynet是为多人在线游戏打造的轻量级服务端框架,使用c+lua实现。使用这套框架的一个好处就是,基本只需要lua,很少用到c做开发,一定程度上提高了开发效率。但skynet文档也相对较少,所以这里利用一点时间学习和总结skynet相关内容,文章这里就讲解下skynet服务的本质与缺陷,希望能有所帮助。
skynet服务的本质
或许我们对skynet服务有着太多的疑问:
skynet服务究竟是什么,为什么有人说服务是一个lua虚拟机,服务与服务之间的通讯是怎样的,为什么服务的内存高居不下, 为什么拿skynet服务和erlang进程做比较?等等。。。而这一切的答案都在代码里面,让我们一步一步解开她的面纱。
服务创建API
先从skynet服务创建的接口说起,方式如下:
- skynet.newservice(name, ...)
看下这个函数的实现:
- -- skynet.lua
- function skynet.newservice(name, ...)
- return skynet.call(".launcher", "lua" , "LAUNCH", "snlua", name, ...)
- end
实际上是调用另外一个服务(.launcher)完成skynet服务的创建。看下launcher服务的处理:
- -- launcher.lua
- -- 处理服务的创建
- local function launch_service(service, ...)
- local param = table.concat({...}, " ")
- local inst = skynet.launch(service, param)
- local response = skynet.response()
- if inst then
- services[inst] = service .. " " .. param
- instance[inst] = response
- else
- response(false)
- return
- end
- return inst
- end
- -- 处理 LAUNCH 类消息
- function command.LAUNCH(_, service, ...)
- launch_service(service, ...)
- return NORET
- end
- -- 处理launcher服务接收到的消息
- skynet.dispatch("lua", function(session, address, cmd , ...)
- cmd = string.upper(cmd)
- local f = command[cmd]
- if f then
- local ret = f(address, ...)
- if ret ~= NORET then
- skynet.ret(skynet.pack(ret))
- end
- else
- skynet.ret(skynet.pack {"Unknown command"} )
- end
- end)
也就是调用 skynet.launch(service, param),实际上 .launcher 服务也是通过这函数实现的。
- -- bootstrap.lua
- local launcher = assert(skynet.launch("snlua","launcher"))
- skynet.name(".launcher", launcher)
为什么要通过另外一个服务创建新的服务?主要目的是为了方便管理所有服务,比如统计,gc,杀掉服务等。