──────────────────────────────────────────────────────────────
┌————————————┐
│▉▉♥♥♥♥♥♥♥♥ 99% │ ♥❤ 鱼沈雁杳天涯路,始信人间别离苦。
└————————————┘
对你的感情正在充电中,请稍侯…
──────────────────────────────────────────────────────────────
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习
──────────────────────────────────────────────────────────────
- 掌握框架是怎么解决问题的 ➔ 掌握框架的数据流
- 掌握框架的核心开发技能 ➔ 掌握增加补充组件(本篇重点)
- 掌握框架的开发思路 ➔ 掌握解决问题的方法
回调函数是actor模型的入口点,它直接将数据传到了lua层。
──────────────────────────────────────────────────────────────
skynet网络层封装以及lua/c接口编程
一、lua(胶水语言)开发,运行速度最快,适合业务逻辑,不能多线程
用户抽象
一个用户对应一个抽象,不一定正确。
底层抽象
1.一个actor一个虚拟机
2.一个c语言接口
3.一个actor一个消息队列
4.一个消息对应一个携程处理
5.一个actor只能跑在一个线程
- 一个actor只能被一个线程调度
- 根据工作线程的权重去调度actor。-1表示:每次只取一个消息处理。0表示:每次取所有消息运行。
actor通过多线程的方式去利用多核cpu。
二、c/lua接口编程
lua数据类型
- boolen:true和false;其中false可以解决table作为array时,元素为nil时造成table取长度未定义的行为。
- number:为interger和double的总称。
- string:常量字符串;这样lua中字符串比较只需要进行地址比较就行了。
- nil:通常表示未定和不存在的两种语义。
- function:与其他语言不同的是,lua中function为第一类型;注意lua中的匿名函数,lua文件可视为一个匿名函数;加载lua文件,可视为执行该匿名函数。
- table: lua中唯一的数据结构;既可以表示hashtable也可以表示array;配合元表就可以定制复杂的功能。
- userdata:完全用户书数据;指向一块内存的指针,通过为userdata设置元素,lua层可以使用该userdata提供的功能;userdata为lua补充了数据结构,解决了lua数据结构单一的问题;可以在c中实现复杂的数据结构吗,生成库继而导出给lua使用;注意:userdata指向的内存需要由lua创建,同时userdata的销毁也交由lua gc来自动回收。
- lightusrerdata:轻量用户书库;也是指向一块内存的指针,但是该内存由c创建,同时它的销毁也有c来完成;不能为他创建元素,轻量用户数据只有类型元素,通常用于lua想使用c的结构,但是不能让lua来释放的结构;在客户端中使用较多。
- thread线程:lua中的携程和虚拟机都是thread类型。
//数组从一开始,并非从零开始
+ local tab={[1]=1,[2]=2,[3]=3,[4]=4}
+ local tab={1,2,3,4,["mark"]=5}
//lua 深入的探讨要等以后啦!可以参看lua5.3的参考手册
lua和c交互时利用一个虚拟栈
重要元表
local tab={[1]=]1,[2]=2,[3]=3,}
local newtab=setmetable{tab,{__index = function(t,k)
return "不存在"
end,
__newindex= function(t,v,k)
print("__newindex",v,k)
error ("不能修改t")
end,
__gc = function(t)
print("gc")
end
})
tab[4]=10
print(tab[4])
- __index:索引table[table]。当table不是表或是表table中不存在key这个键时,这个时间被触发。此时,会对出table相应得元方法。
- __newindex:索引赋值table[key]=value。和索引事件类似,它发生在table不是表或时表table中不存在key这个键的时候。此时,会读出table相应的方法。
- __gc:元表中用一个以字符串“__gc”为索引的域,那么就标记了这个对象需要的触发终结器。除去lightusrerdata这个数据类型,其他的数据类型都需要使用__gc。
注意事项
- 只有table和userdata对象有独自的元表,其他类型只有类型元素。
- 只有table可以在lua中修改设置元表。
- userdata 只能在c中修改设置元表,lua中不能修改userdata元表。
local co=coroutine.create(function(arg1))
local ret1 =arf1 + 1
local arg2=coroutine.yield(ret1)
local ret2=arg2+1
return ret2
end)
local co1=coroutine.runing()
local arg1=1
local ok,ret1,ret2
ok,ret1=coroutine.resume(co,arg1)
print(co1,ok,ret1)
ok,ret2=coroutine.resume(co,ret1)
print(co1,ok,ret2)
闭包
local args
local function func()
args = "hello"
end
local funtion func()
local args ="hello"
return funtion()
args =args.. "world"
return args
end
end
local ff=func()
print(ff()) //hello
print(ff()) //hello world
print(ff()) //hello world world
需要注意的是,在c语言中0表示false,而在lua脚本中0是一个数值,它表示true。
not nil 和not false相当于c语言的true,~=表示不等于。
虚拟栈
- 栈中只能存放lua类型的值,如果i想用的c的类型存储的栈中,需要将c类型转换为lua类型;
- c调用lua,每一个下协程都有一个栈;lua调用c的函数都得到一个新的栈,独立于之前的栈;
- c调用lua,每一个协程都有一个栈;
- c创建虚拟机时,伴随创建了一个主协程,默认创建一个虚拟栈;
- 无论何时Lua调用c,它都只保证至少有LUA_MINSTACK这么多的堆栈空间可以使用。LUA_MINSTACK一般被定义为20.因此,只要你不是不断的把数据压栈,通常你不用关心堆栈的大小。
- lua调c会自动释放栈,而c调用lua不会自动释放栈。
编程接口步骤及规范
1.头文件
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
2.导出模块
每一个模块都需要找出一个这样的接口。
int luaopen_uv_c(lua_state *L)
对应的lua方面
require "uv.c"
3.导出接口
static const luaL_Reg l[]={
{"echo",lecho},
{NULL,NULL},
};
int luaopen_uv_c(lua_State * L){
luaL_newlibtable(L,l); //1
lua_pushinteger(L,0); //2
lua_setfuncs(L,l,1); //上值
//luaL_newlib(L,1);
return 1;
}
local so=require "uv.c"
so.echo
//echo为lua使用,lecho为c语言实现接口
4.写接口
//只需要一个参数,lua_***表示操作lua虚拟栈。
static int
lecho (lua_State *L){
lua_Integer n=lua_tointeger(L,lua_upvalueindex(1));
n++;
const char * str =lua_tostring(L,-1);
fprintf(stdout,"[n=%lld]---%s \n",n,str);
lua_pushinteger(L,n);
lua_replace(L,lua_upvalueindex(1));
return 0;
}
- lua是不能直接调用c语言的,需要将c语言封装成库。
- 闭包是语言的一个特性,相当于类额私有成员。
5.Makefile 编译成动态库(待完善)
三、c服务(actor待完善)