【原创代码分享:如何正确的将lua嵌入到c语言中(linux服务端方向)】

qq120848369 2013-04-15 07:48:03
项目说明:
以c编写基于epoll的单线程网络服务端,嵌入lua以便支持脚本编写请求处理逻辑,完美支持yield。

工作原理为:
一,c服务端框架:
1) 一个session对应一个coroutine,所有session共享同一个main thread。coroutine的引用计数在main thread的一个table中维持, 即fd->coroutine的映射。
2)负责网络I/O,负责request的解析并将其加入到所属session的request-queue尾部。根据session(连接,会话)的request-queue是否为空并处于coroutine yield的状态(wait_req标记位)决定是否需要调用lua_resume唤醒lua处理request-queue。
3)每个session都有独立的定时器检查coroutine状态,如果coroutine因为语法等任何错误而死亡,能够及时的探测并踢除session的连接。

二,lua扩展框架中:
1)用户编写main.lua,填写业务回调callback函数, 之后调用start_consume即进入了请求处理循环。
2)start_consume将检查request queue来获取一个request,如果没有request则yield挂起等待c框架唤醒,否则将request传给用户callback进行处理。
3)并提供给了用户一些lua api进行编程, 现在只提供了一个发送报文的接口, 定时器, 后续会提供 建立连接/读/写 等异步编程接口.

不便之处:
1,由于c服务端只有一个main thread(全局lua_State),每个session都是在main thread创建的coroutine thread上执行的,所以是通过设置coroutine.resume(callback)中的callback的_ENV(第一个upvalue)实现每个coroutine都拥有独立的session全局变量。结果就是,在实现lua module的时候,由于require继承全局环境而非callback的环境, 导致在开发时不得不将session变量从main.lua(只有main.lua的_ENV里可见session)向下传递。(@_@,但愿你看代码的时候能够体会)

其他说明:
为了体现lua给c带来了什么好处, 我开发了一个lua api叫做block_alarm,其作用是阻塞N毫秒之后执行回调函数,这对于lua开发者来说是看似阻塞的,但对于c服务端框架来说是完全异步的,并不会阻塞其他连接的处理。

lua api使用示例:
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)


sapi是我提供的基础lua module,用于和c服务端进行交互,一共就3个接口,大家看一下:

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志同道合的朋友一起研究lua,并给该项目的设计思路中错误或者不足的地方给予指正,因为我也是完全个人探索,没有看过什么开源lua服务端实现。

下载地址:
http://pan.baidu.com/share/link?shareid=428565&uk=2686094642


项目价值:
1,封装了可复用的若干组件,包括:
1)queue队列
2)Minheap最小堆
3) simple_io网络事件库
2,演示了lua coroutine的运用。

即便对lua没有兴趣的同学,也建议读一下simple_io,queue这些公共库的实现。
...全文
460 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
jamesguo37 2014-05-28
  • 打赏
  • 举报
回复
其实就是将lua嵌入到应用程序中去。
jamesguo37 2014-05-28
  • 打赏
  • 举报
回复
hi lz: 小弟刚学lua不久,想了解一下lua能否获取正在运行的程序的内部数据。 如:main.exx依赖libtest.so,此时main.exx正在运行。而lua通过调用libtest.so的接口,能否获取到libtest.so内部的数据。 试了一下是不行的(lua运行的时候也是创建了一个进程,所以没法获取到数据),有什么办法可以做到吗
恨天低 2013-10-11
  • 打赏
  • 举报
回复
已有ngx_lua模块,开源openresty.
miliggate 2013-04-17
  • 打赏
  • 举报
回复
新淫表示没有用过lua perl倒是用过
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 22 楼 wallwind 的回复:
引用 21 楼 qq120848369 的回复:引用 18 楼 wallwind 的回复:引用 12 楼 qq120848369 的回复:引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。 小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结……
你说的东西只是我项目里必须做的事情之一, 如果你能谦虚点, 不如花点功夫了解一下.
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 22 楼 wallwind 的回复:
引用 21 楼 qq120848369 的回复:引用 18 楼 wallwind 的回复:引用 12 楼 qq120848369 的回复:引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。 小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结……
有耐心了解一下为什么值得拿出来, 如果你真知道我做了什么, 我愿意倾听: http://www.cnblogs.com/xmpp/archive/2013/04/17/3027044.html
wintree 2013-04-17
  • 打赏
  • 举报
回复
引用 21 楼 qq120848369 的回复:
引用 18 楼 wallwind 的回复:引用 12 楼 qq120848369 的回复:引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。 小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结构体注册。又很好的扩展性.内存使用稳定。 ……
没有自我膨胀,只是觉得你回复我的的时候,你用“小朋友”一词,也是明显有对我。。。,我自然用“小小朋友”,你觉得你的很牛逼,就不要来炫耀了。你直接让全世界的人都说你很牛逼就行了。让你们老大李彦宏直接升你职也行。 回归正题:我的lua使用就是是这么搞的。就是把一些函数注册进去,然后lua脚本使用注册的函数,完成我想要的业务逻辑。 还有,我不是大神,脏了你的帖子是我不对。我都没说啥你就这德行,感觉你也,而且我并不想和你互喷。 如果我回复脏字,你可以直接举报我。敬请期待。
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 18 楼 wallwind 的回复:
引用 12 楼 qq120848369 的回复:引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。 小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结构体注册。又很好的扩展性.内存使用稳定。
严重的自我膨胀, 劝你早日落地。
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 18 楼 wallwind 的回复:
引用 12 楼 qq120848369 的回复:引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。 小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结构体注册。又很好的扩展性.内存使用稳定。
劝你别脏了我的帖子, 谢谢大神.
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 18 楼 wallwind 的回复:
引用 12 楼 qq120848369 的回复:引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。 小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结构体注册。又很好的扩展性.内存使用稳定。
呵呵 - -, 不值得评价什么, 好幼稚.
wintree 2013-04-17
  • 打赏
  • 举报
回复
引用 12 楼 qq120848369 的回复:
引用 11 楼 wallwind 的回复:不错, 不过感觉你把lua和c交互让你搞复杂了。。。。 没有实践过不要乱说哦, 小朋友。
小小朋友,主要是我搞的 c+lua 是使用static struct luaL_Reg 结构体注册。又很好的扩展性.内存使用稳定。
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
lua module里都没用local, 啊哈哈,大家不要学我。
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 15 楼 lile1234_show 的回复:
实践过复杂状态机server编码的同学,如果没接触过lua,没接触过coroutine,可以趁这个机会做一个了解哦。
lee_鹿游原 2013-04-17
  • 打赏
  • 举报
回复
Red_angelX 2013-04-17
  • 打赏
  • 举报
回复
楼主厉害啊 学习下
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
说点感触: 1,之前也做过2个lua server了, 实现方法各不相同, 都是在探索阶段。 最终发现,每个连接对应一个常驻的coroutine比 “每个连接一个lua_State”或者每个请求一个coroutine都要更合理,所以又尝试做了一个这个server,对内存以及性能都有很大的提升。 2,在实践过程中,对lua资源的管理是比较需要费心的部分。 1) 根据我个人经验, 开发过程尽量使用lightuserdata而非userdata,因为可以避免不必要的内存分配直接使用C中原有数据,但缺点就是只能使用面向过程接口,没法设置metatable,算是一个不便之处。 2) yield最好做在lua module里,因为lua5.2之前是不支持yieldk系列接口的,并且在c层做yield会丢失C堆栈,所以做在Lua栈里来保存断点会更简单。 3) 在做此类lua嵌入c server的程序结构中,应当首先开发lua与c的框架层,能够正确解析lua脚本,在这一个阶段需要考虑好将要暴露给lua module的api能否被有效的支持,比如是否希望支持带有yield的异步lua接口,那么框架是需要做好支持的。 其次,才是为lua使用者开发api,并在c中写对应的lua api实现。 最后,我们可以用支持好的lua api编写脚本,并在C框架下解释执行。 4) lua资源一定要清楚的知道其引用计数是多少,否则极有可能丢失引用而被gc,导致C层出现非法内存访问。 5) 最后,我认为正统的lua程序,应该做好c框架,并使用c实现api,并使用lua包裹c api暴露给最终用户。 3,当然lua基础功很重要,对协程,环境,等等的深刻认识是离不开的,只能通过自己实践摸索了。
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
引用 11 楼 wallwind 的回复:
不错, 不过感觉你把lua和c交互让你搞复杂了。。。。
没有实践过不要乱说哦, 小朋友。
wintree 2013-04-17
  • 打赏
  • 举报
回复
不错, 不过感觉你把lua和c交互让你搞复杂了。。。。
qq120848369 2013-04-17
  • 打赏
  • 举报
回复
BUG修复了噢,大家速速来下载吧: http://pan.baidu.com/share/link?shareid=431150&uk=2686094642 2013年04月17日: 1,修复了net_free中调用net_free_session的实现bug。 2,修复了sio_timer中long long截断int引起的定时器bug。
qq120848369 2013-04-15
  • 打赏
  • 举报
回复
谁来帮我找找minheap里的bug,竟然堆顶比子堆还大,汗汗汗。
加载更多回复(8)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧