摘自:http://www.daileinote.com/computer/openresty/03
我们知道,openresty 使用的开发语言为 Lua,内置了 LuaJIT 解释器,速度比 Lua 官方解释器要快很多。
LuaJIT 基于 Lua 5.1,但在不破坏兼容性的前提下适当引入了一些 5.2 和 5.3 的语言特性,还提供了很多特别的优化和库,例如 table.new、bit、ffi。LuaJIT 是开源的,官网地址为 http://luajit.org
continue Lua 语言不支持 continue 语法,有时候很不方便,好在 LuaJIT 加入了 Lua 5.2 的 goto 语句,变相的实现了 continue。goto 语句需要配合标签 ::label::使用,例如
1 2 3 4 5 6 7 8 9 10 11 12 for i=0 ,6 ,1 do if i<5 then goto continue else print (i) end ::continue:: end [root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua 5 6
bit LuaJIT 为 Lua5.1 增加了对于位的处理能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 local bit = require ("bit" )local x = 5 local y = 7 print (bit.band(x,y)) print (bit.bor(x,y)) print (bit.bnot(x)) print (bit.bxor(x,y)) print (bit.lshift(x,1 )) print (bit.rshift(x,1 )) [root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua 5 7 -6 2 10 2
ffi ffi 是 LuaJIT 里最强大也是最有价值的一个库,极大的简化了在 Lua 里调用 c/c++ 函数的工作,而且执行效率更高。
ffi 不仅可以调用系统函数和 openresty/nginx 内部的 C 函数,还可以加载 so 形式的动态库,调用动态库的函数,从而轻松扩展 Lua 的功能。
ffi.load 加载 *.so 动态库ffi.null 相当于c的 NULLffi.string 把C指针指向的内存转化为 Lua 字符串ffi.cdef 声明C的数据结构ffi.typeof 声明一个 C 类型ffi.new 利用上面的 C 类型分配内存ffi.C C函数所在的全局命名空间,可以用 . 来执行
1 2 3 4 5 local ffi = require ("ffi" )ffi.cdef[[ int printf(const char *fmt, ...); ]] ffi.C.printf("Hello %s!\n" , "world" )
在 Lua 里想要跟C交互的都是 cdata 类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 local ffi = require ("ffi" )ffi.cdef[[ int printf(const char *fmt, ...); ]] ffi.C.printf("直接打印失败 %d\n" , 10 ) t1 = ffi.typeof("int" ) local cint_a = ffi.new(t1, 10 )local cint_b = ffi.new("int" , 11 )local cint_c = t1(12 )ffi.C.printf("第二种方式成功 %d %d %d\n" , cint_a, cint_b, cint_c) [root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua 直接打印失败 0 第二种方式成功 10 11 12
对于字符串,ffi.new 第一个参数只能是 const char *、const char[size] 或 char[size]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 local ffi = require ("ffi" )ffi.cdef[[ int printf(const char *fmt, ...); ]] local s_a = ffi.new("const char *" , "http://www.freecls.com" )local s_b = ffi.new("char [5]" , "hello" )local s_c = ffi.new("const char [5]" , "hello" )ffi.C.printf("%s %s %s\n" , s_a, s_b, s_c) print (s_a)print (ffi.string (s_a))[root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua http://www.freecls.com hello hello cdata<const char *>: 0x4151b608 http://www.freecls.com
对于结构体,可以使用表格赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 local ffi = require ("ffi" )ffi.cdef[[ int printf(const char *fmt, ...); struct son{ int c; int d; const char *name; }; struct person { int a; int b; struct son e; }; struct eat{ char *name; char sex[7]; }; ]] local ss = ffi.new("const char *" , "freecls" )local p1 = ffi.new("struct person" , {1 ,2 ,{3 ,4 , ss}})p1.e.name = "changed" print (ffi.string (p1.e.name))local p2 = ffi.new("struct eat" )p2.name = ffi.new("char[7]" ) ffi.copy(p2.name, "freecls" ) ffi.copy(p2.sex, "1234567" ) print (ffi.string (p2.sex))p2.sex = "3333333" print (ffi.string (p2.sex))[root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua changed 1234567 3333333
加载外部动态库
1 2 3 4 5 6 7 8 //main.c int add(int x, int y){ return x + y; } int add1(int *x, int *y){ return *x + *y; }
接下来编译成动态库并拷贝到默认搜索路径,我的是 /lib64
1 2 gcc -g -fPIC -Wall main.c -shared -o libtest.so cp libtest.so /lib64/
int 型指针可以用数组模拟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 local ffi = require ("ffi" )ffi.cdef[[ int add(int,int); int add1(int *, int*); ]] local test = ffi.load ("test" )print (test.add(1 ,2 ))local i1 = ffi.new("int[1]" , 3 )local i2 = ffi.new("int[1]" , {4 })print (test.add1(i1, i2))[root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua 3 7
如果希望上面的库函数可以在 ffi.C 里调用,那么 load 第二个参数设为 true。
1 2 3 4 5 6 7 8 9 10 11 local ffi = require ("ffi" )ffi.cdef[[ int add(int,int); int add1(int *, int*); ]] local test = ffi.load ("test" , true )print (ffi.C.add(1 ,2 ))[root@192 lua]# /usr/local /openresty/luajit/bin/luajit tmp.lua 3
更多用法请参考 ffi tutorial