四、FFI和第三方模块

目录

FFI
如何调用外部C库函数?
Openresty自带很多luaJIT库
第三方模块
FFI FFI 库,是 LuaJIT 中最重要的一个扩展库。它允许从纯 Lua 代码调用外部 C 函数,使用 C 数据结构。有了它,就不用再像 Lua 标准 math 库一样,编写 Lua 扩展库。把开发者从开发 Lua 扩展 C 库(语言/功能绑定库)的繁重工作中释放出来。学习完本小节对开发纯 ffi 的库是有帮助的,像 lru-resty-lrucache 中的 pureffi.lua,这个纯 ffi 库非常高效地完成了 lru 缓存策略。
简单解释一下 Lua 扩展 C 库,对于那些能够被 Lua 调用的 C 函数来说,它的接口必须遵循 Lua 要求的形式,就是 typedef int (*lua_CFunction)(lua_State* L),这个函数包含的参数是 lua_State 类型的指针 L 。可以通过这个指针进一步获取通过 Lua 代码传入的参数。这个函数的返回值类型是一个整型,表示返回值的数量。需要注意的是,用 C 编写的函数无法把返回值返回给 Lua 代码,而是通过虚拟栈来传递 Lua 和 C 之间的调用参数和返回值。不仅在编程上开发效率变低,而且性能上比不上 FFI 库调用 C 函数。
FFI 库最大限度的省去了使用 C 手工编写繁重的 Lua/C 绑定的需要。不需要学习一门独立/额外的绑定语言——它解析普通 C 声明。这样可以从 C 头文件或参考手册中,直接剪切,粘贴。它的任务就是绑定很大的库,但不需要捣鼓脆弱的绑定生成器。
FFI 紧紧的整合进了 LuaJIT(几乎不可能作为一个独立的模块)。JIT 编译器在 C 数据结构上所产生的代码,等同于一个 C 编译器应该生产的代码。在 JIT 编译过的代码中,调用 C 函数,可以被内连处理,不同于基于 Lua/C API 函数调用。
如何调用外部C库函数?
1、加载FFI库。
2、为函数添加C声明。
3、调用命名的C函数。

访问LuaJIT官方网站可以查看怎么使用它

参考上面网站示例,编写call_C.lua

local ffi = require("ffi") --调用FFI库 --声明print函数方法 ffi.cdef[[ int printf(const char *fmt, ...); ]] --使用C函数直接调用printf方法 ffi.C.printf("Hello %s!", "world")

nginx.conf添加调用代码
location /call_C {
content_by_lua_file lua/call_C.lua;
}
reload nginx后,在控制台执行语句
curl -lhttp://127.0.0.1/call_C.lua
发现返回值为空,这是因为我们没有调用LuaJIT执行
进入目录/usr/local/openresty/luajit/bin
四、FFI和第三方模块
文章图片

该目录下有luajit
执行语句
luajit-2.1.0-beta3 /usr/local/openresty/nginx/lua/call_C.lua
返回结果
四、FFI和第三方模块
文章图片

这里也可以添加给luajit环境变量
四、FFI和第三方模块
文章图片

这样在控制台就可以直接输入命令了
四、FFI和第三方模块
文章图片

Openresty自带很多luaJIT库 在/usr/local/openresty/lualib/resty可以看到
四、FFI和第三方模块
文章图片

以random.lua为例
local ffi = require "ffi" local ffi_new = ffi.new local ffi_str = ffi.string local C = ffi.C --local setmetatable = setmetatable --local error = errorlocal _M = { _VERSION = '0.11' }ffi.cdef[[ int RAND_bytes(unsigned char *buf, int num); int RAND_pseudo_bytes(unsigned char *buf, int num); ]]function _M.bytes(len, strong) local buf = ffi_new("char[?]", len) if strong then if C.RAND_bytes(buf, len) == 0 then return nil end else C.RAND_pseudo_bytes(buf,len) endreturn ffi_str(buf, len) endreturn _M

这里声明了两个随机数的函数,谷歌搜索发现该函数是openssl中自带的 ,说明我们可以直接在Lua代码里做函数声明,就可以直接调系统的C函数,避免使用Lua实现
四、FFI和第三方模块
文章图片


第三方模块 例如Openresty要发送HTTP到baidu.com
我们需要借助第三方的模块 resty http
1、下载好后解压,将压缩包内lib中的http_lua和http_headers_lua拷贝到/usr/local/openresty/lualib/resty目录中
四、FFI和第三方模块
文章图片

2、在nginx.conf中写入location
四、FFI和第三方模块
文章图片

3、在server模块中写入域名解析器
四、FFI和第三方模块
文章图片

4、编写baidu.lua代码
local http = require("resty.http") --创建http客户端实例 local httpc = http:new()local resp,err = httpc:request_uri("http://www.baidu.com", { method = "GET", headers = {["User-Agent"]="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"} })if not resp then ngx.say("request error:",err) return else --响应体 ngx.say(resp.body) endhttpc:close()

5、在浏览器执行 127.0.0.1/baidu
就可以跳转百度的页面
四、FFI和第三方模块
文章图片

【四、FFI和第三方模块】
另外的POST例子 参考 openresty 中lua操作http请求

    推荐阅读