在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
如题, 代码做的事情: 将lua嵌入到了c语言编写的网络服务端中,支持yield异步API的编写,安全的管理会话与lua资源。
工作原理: 一,c服务端框架:
特别说明: 为了展示lua给c服务端开发带来了什么改变, 我开发了一个lua api叫做block_alarm,其作用是阻塞N毫秒之后执行回调函数,这对于lua开发者来说是看似阻塞的,但对于c服务端框架来说是完全异步的,并不会阻塞其他连接的并发处理,其中透露出lua coroutine的鲜明特色。
读者群体: lua的协程(coroutine)的益处, 对于拥有编写过复杂状态机服务端(例如nginx, lighttpd等类似插件与busy loop架构服务端)经验的程序员会有极大的共鸣,协程带来的不仅是更少的cpu损耗, 而是将c语言中的维护状态机的工作转移给了coroutine,让程序扩展性与简洁性都得到了极大的提高, 解放了复杂状态机服务的复杂度。 本代码对上述经历的程序员将有不少指导意义,而对于很多希望涉足游戏开发职位的同学也是必不可少的编程技能之一,争取做一个开发lua server框架而不是只会lua语法的专业游戏开发人员吧。
程序说明: 开发人员在此框架下,只需要关注请求的处理与应答,即使用lua语法编写请求处理脚本,需要使用框架提供的lua api实现功能(即完成与c服务框架的交互)。
这里举了一个最基本的例子,演示了lua coroutine对于慢处理请求的异步化能力: sapi = require('sapi') require('os') function cb(sess, req) first = "curtime=" .. tostring(os.time()) .. " req=" .. req sapi.write_response(sess, first) function alarm_cb(arg) second = "curtime=" .. tostring(os.time()) .. " res=" .. req sapi.write_response(sess, second) end sapi.block_alarm(sess, 4000, alarm_cb, req) end sapi.start_consume(session, cb) 我编写了一个请求处理函数叫做cb,传入给sapi.start_consume就可以由框架完成剩余的处理。 在cb里,我先向客户端写回了first这行应答,然后调用阻塞定时器睡眠4000毫秒,并在定时器结束时向客户端写回second这行应答。其中,block_alarm虽然将lua脚本的执行挂起了,但对于c框架来说这是完全异步的,不会阻塞其他客户端请求的处理(coroutine的灵魂在这里)。
可以看到上面使用到了sapi这个module,当前只实现了lua入口接口,一个应答接口,以及一个演示coroutine特性的block_alarm接口。 module('sapi', package.seeall) --session api local capi = require('capi') --get a request from session->reqs if not empty, --otherwise it will do yield. --you have to notice that we are already in coroutine here function get_req(session) req = capi._get_req(session) while req == nil do coroutine.yield() req = capi._get_req(session) end return req end function write_response(session, content) return capi._write_response(session, content) end function block_alarm(session, timeout, callback, arg) capi._block_alarm(session, timeout) coroutine.yield() callback(arg) end function start_consume(session, cb) while true do req = get_req(session) cb(session, req) end end 可以看到这个lua module中又使用了capi module,这是一个c语言编写的lua module,用于与c服务端进行交互,而sapi module是一个lua编写的module,作为capi的wrapper(技术限制:因为在lua中yield可以保存堆栈,而在c里做yield只在5.2后实现, 并且会破坏C堆栈),这是市面上lua与c交互基本公知的组织形式。
协议的解析在C中实现,目前支持telnet的行请求形式,即只要通过telnet连接server即可进行交互。另外,编译代码前别忘了改一下Makefile里的lua相关的依赖路径,别忘了编译liblua.a时修改Makefile增加-fPIC编译选项(写lua扩展必备),另外也别忘了在启动服务前export一下你的LUA_PATH和LUA_CPATH,可以参考envrion.sh。
上面我编写的cb实际执行效果是什么样呢,看个截图吧:
终端1
终端2
终端3
继续在telnet上折腾它吧,下载地址:http://pan.baidu.com/share/link?shareid=431706&uk=2686094642 即便你不懂lua,但对服务端开发有兴趣,读一下util下的simple_io网络事件库吧:)
文件组织:
如题, 代码做的事情: 将lua嵌入到了c语言编写的网络服务端中,支持yield异步API的编写,安全的管理会话与lua资源。
工作原理: 一,c服务端框架:
特别说明: 为了展示lua给c服务端开发带来了什么改变, 我开发了一个lua api叫做block_alarm,其作用是阻塞N毫秒之后执行回调函数,这对于lua开发者来说是看似阻塞的,但对于c服务端框架来说是完全异步的,并不会阻塞其他连接的并发处理,其中透露出lua coroutine的鲜明特色。
读者群体: lua的协程(coroutine)的益处, 对于拥有编写过复杂状态机服务端(例如nginx, lighttpd等类似插件与busy loop架构服务端)经验的程序员会有极大的共鸣,协程带来的不仅是更少的cpu损耗, 而是将c语言中的维护状态机的工作转移给了coroutine,让程序扩展性与简洁性都得到了极大的提高, 解放了复杂状态机服务的复杂度。 本代码对上述经历的程序员将有不少指导意义,而对于很多希望涉足游戏开发职位的同学也是必不可少的编程技能之一,争取做一个开发lua server框架而不是只会lua语法的专业游戏开发人员吧。
程序说明: 开发人员在此框架下,只需要关注请求的处理与应答,即使用lua语法编写请求处理脚本,需要使用框架提供的lua api实现功能(即完成与c服务框架的交互)。
这里举了一个最基本的例子,演示了lua coroutine对于慢处理请求的异步化能力: sapi = require('sapi') require('os') function cb(sess, req) first = "curtime=" .. tostring(os.time()) .. " req=" .. req sapi.write_response(sess, first) function alarm_cb(arg) second = "curtime=" .. tostring(os.time()) .. " res=" .. req sapi.write_response(sess, second) end sapi.block_alarm(sess, 4000, alarm_cb, req) end sapi.start_consume(session, cb) 我编写了一个请求处理函数叫做cb,传入给sapi.start_consume就可以由框架完成剩余的处理。 在cb里,我先向客户端写回了first这行应答,然后调用阻塞定时器睡眠4000毫秒,并在定时器结束时向客户端写回second这行应答。其中,block_alarm虽然将lua脚本的执行挂起了,但对于c框架来说这是完全异步的,不会阻塞其他客户端请求的处理(coroutine的灵魂在这里)。
可以看到上面使用到了sapi这个module,当前只实现了lua入口接口,一个应答接口,以及一个演示coroutine特性的block_alarm接口。 module('sapi', package.seeall) --session api local capi = require('capi') --get a request from session->reqs if not empty, --otherwise it will do yield. --you have to notice that we are already in coroutine here function get_req(session) req = capi._get_req(session) while req == nil do coroutine.yield() req = capi._get_req(session) end return req end function write_response(session, content) return capi._write_response(session, content) end function block_alarm(session, timeout, callback, arg) capi._block_alarm(session, timeout) coroutine.yield() callback(arg) end function start_consume(session, cb) while true do req = get_req(session) cb(session, req) end end 可以看到这个lua module中又使用了capi module,这是一个c语言编写的lua module,用于与c服务端进行交互,而sapi module是一个lua编写的module,作为capi的wrapper(技术限制:因为在lua中yield可以保存堆栈,而在c里做yield只在5.2后实现, 并且会破坏C堆栈),这是市面上lua与c交互基本公知的组织形式。
协议的解析在C中实现,目前支持telnet的行请求形式,即只要通过telnet连接server即可进行交互。另外,编译代码前别忘了改一下Makefile里的lua相关的依赖路径,别忘了编译liblua.a时修改Makefile增加-fPIC编译选项(写lua扩展必备),另外也别忘了在启动服务前export一下你的LUA_PATH和LUA_CPATH,可以参考envrion.sh。
上面我编写的cb实际执行效果是什么样呢,看个截图吧:
终端1
终端2
终端3
继续在telnet上折腾它吧,下载地址:http://pan.baidu.com/share/link?shareid=431706&uk=2686094642 即便你不懂lua,但对服务端开发有兴趣,读一下util下的simple_io网络事件库吧:)
文件组织:
|
请发表评论