前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教你用OpenResty里的FFI

手把手教你用OpenResty里的FFI

作者头像
LA0WAN9
发布2021-12-14 09:01:50
7380
发布2021-12-14 09:01:50
举报
文章被收录于专栏:火丁笔记

了解 OpenResty 的人应该知道,OpenResty 原本的 API 都是基于 C 实现的,不过在新版里都已经改成了基于 FFI 实现的,为什么这么做?因为 FFI 在效率上更有优势,除此以外,FFI 还有一个优点是可以很便利的和 C 交互,我们不妨设想一下,C 语言有那么多成熟的库,通过 FFI,我们可以轻而易举的引入到自己的应用中,何乐而不为呢?

本文通过 Hashids 手把手教你用 OpenResty 里的 FFI。说起 Hashids,它的功能是把一个正整数转换成一个相对更短的唯一 ID,比如把 123456789 转换成 NRv345。基本上主流语言都实现了 Hashids,当然也有 Lua 版本,不过本文即然是讲解 FFI 的,自然不会采用此版本,实际上我们使用的是 C 版本。

下载了 C 版本的 Hashids 源代码之后,第一件事是编译出动态链接库:

代码语言:javascript
复制
➜ gcc -shared -fPIC -o libhashids.so /path/to/hashids.c
➜ gcc -dynamiclib -fPIC -o libhashids.dylib /path/to/hashids.c

不同操作系统使用不同的命令:Linux 用前一个,Mac 用后一个。此外还需要把库文件放到系统路径里,同样有操作系统差异,Linux 用 ldconfig,Mac 用 install_name_tool,细节不赘述,让我们直接看看如何通过 FFI 来使用 C 语言的动态链接库,简单说和把大象放冰箱一样,分三步:首先通过 ffi.cdef 添加头文件;然后通过 ffi.load 加载动态链接库,最后把 C 语言的操作步骤翻译成 Lua 代码。看代码吧:

代码语言:javascript
复制
local ffi = require "ffi"

ffi.cdef[[
struct hashids_s {
    char *alphabet;
    char *alphabet_copy_1;
    char *alphabet_copy_2;
    size_t alphabet_length;

    char *salt;
    size_t salt_length;

    char *separators;
    size_t separators_count;

    char *guards;
    size_t guards_count;

    size_t min_hash_length;
};
typedef struct hashids_s hashids_t;

void
hashids_free(hashids_t *hashids);

hashids_t *
hashids_init(const char *salt);

size_t
hashids_encode(hashids_t *hashids, char *buffer, size_t numbers_count,
    unsigned long long *numbers);

size_t
hashids_decode(hashids_t *hashids, const char *str,
    unsigned long long *numbers, size_t numbers_max);

size_t
hashids_estimate_encoded_size(hashids_t *hashids, size_t numbers_count,
    unsigned long long *numbers);
]]

local id = 123456789

local C = ffi.load("hashids")
local hashids = C.hashids_init("this is my salt")
local numbers = ffi.new("unsigned long long[1]", id)
local size = C.hashids_estimate_encoded_size(hashids, 1, numbers)
local buffer = ffi.new("char[?]", size)
local length = C.hashids_encode(hashids, buffer, 1, numbers)
local hashid = ffi.string(buffer, length)
local str = ffi.new("char[?]", #hashid, hashid)
numbers = ffi.new("unsigned long long[1]")
C.hashids_decode(hashids, str, numbers, -1)
C.hashids_free(hashids)

ngx.say("id: ", id)                       -- id: 123456789
ngx.say("hashid: ", hashid)               -- hashid: NRv345
ngx.say("decode: ", numbers[0])           -- decode: 123456789ULL
ngx.say("decode: ", tonumber(numbers[0])) -- decode: 123456789

在使用 Lua 操作动态链接库的时候,和 C 语言总体保持一致,常见的整数,字符串等数据类型都可以直接使用,唯一需要注意的是 C 语言的指针类型无法直接映射到 Lua 的数据类型,此时的变通做法是通过 ffi.new 声明一个「只有一个元素的数组」。

LuaJIT FFI 不仅可以调用 C 语言,还可以调用其他语言,比如 Go,详情可以参考:

关于 LuaJIT FFI 更多信息,建议浏览官方文档。下面文档也值得一看:

此外,luapower 上能找到不少使用 FFI 的代码,建议多看看。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档