四、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 -l  http://127.0.0.1/call_C.lua

发现返回值为空,这是因为我们没有调用LuaJIT执行

进入目录/usr/local/openresty/luajit/bin

该目录下有luajit

执行语句

luajit-2.1.0-beta3 /usr/local/openresty/nginx/lua/call_C.lua

返回结果

这里也可以添加给luajit环境变量

这样在控制台就可以直接输入命令了

Openresty自带很多luaJIT库

在/usr/local/openresty/lualib/resty可以看到

四、FFI和第三方模块_第1张图片

以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 = error


local _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)
    end

    return ffi_str(buf, len)
end


return _M

这里声明了两个随机数的函数,谷歌搜索发现该函数是openssl中自带的 ,说明我们可以直接在Lua代码里做函数声明,就可以直接调系统的C函数,避免使用Lua实现

四、FFI和第三方模块_第2张图片 

 

第三方模块

 例如Openresty要发送HTTP到baidu.com

我们需要借助第三方的模块 resty http

1、下载好后解压,将压缩包内lib中的http_lua和http_headers_lua拷贝到/usr/local/openresty/lualib/resty目录中

四、FFI和第三方模块_第3张图片

2、在nginx.conf中写入location

四、FFI和第三方模块_第4张图片

3、在server模块中写入域名解析器

四、FFI和第三方模块_第5张图片

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)
end

httpc:close()

5、在浏览器执行 127.0.0.1/baidu

就可以跳转百度的页面

四、FFI和第三方模块_第6张图片

 

另外的POST例子 参考 openresty 中lua操作http请求

你可能感兴趣的:(OpenResty)