为什么要在nginx中使用lua嵌入c程序?
1.性能上的考虑,lua毕竟是一个脚本语言,对于某些特定的功能如果用纯lua来实现性能上一般都会比用c要逊色一些。
2.没有现成的库供我们使用,实际上互联网上已经有很多现成的第三方lua库供我们使用,比如读取redis数据的resty.redis;将json转化为lua本地数据格式的cjson等。当找不到合适我们使用的第三方库的时候,我们就需要自己动手了。当然如果能够直接使用lua来写一个满足我们自己使用的库也是可以的,如果考虑到性能问题,用c来实现是一个不错的选择。
我们这里打算实现两个方法
1.对一个字符串做hash并对其hash值取摸,在lua中我们可以这样调用该方法:
local value = demo.mod("abcdefe",8);
其中demo是我们写好的c库;
mod方法的第一个参数是要进行取摸的字符串;
第二个参数是摸;
2.由于lua中的时间函数无法精确到毫秒级,我们这里实现一个可以获取系统毫秒的时间:
local time = demo.time();
具体实现
首先引入lua的c api头文件和我们用到的时间头文件
实现一个murmurhash算法,用来hash我们的字符串
typedef unsigned long long uint64_t;
typedef long long int64_t;
typedef long int int32_t;
我们看到上面这个方法是一个纯c函数,lua如何于c传递数据呢?我们看下面这个方法
好了,有拉上面mod方法的解释,我们获取系统时间的方法就比较容易理解了。
实现获取当前毫秒级的系统时间
接下来就是要讲我们写好的c函数注册到lua中了
方法格式: int luaopen_xxx(lua_State *L)
其它都是固定的,只有xxx使我们自定义的库名,我们这里给它起个名字叫demo
下面这个是我们从5.2中拿过来的代码
实际上在lua5.1中使用lua_register()和luaL_register()等方法同样可以将c函数注册到lua中。
使用方法
将上面的代码编译成.so共享库
cc -c -O3 -Wall -pedantic -DNDEBUG -I/luajit/include/luajit-2.1 -fpic -g -o lua_demo.o lua_demo.c
cc -bundle -undefined dynamic_lookup -o demo.so lua_demo.o
/luajit/include/luajit-2.1 是luajit的头文件所在目录
lua_demo.c 是我们上面编写好的代码
将demo.so拷贝到一个指定目录,比如我们这里是/nginx/lualib
在nginx中像这样使用
lua_package_cpath "/nginx/lualib/?.so;;"; //注意是两个分号
server {
listen 80;
location ~ /test {
content_by_lua '
local demo = require "demo";
local index = demo.mod("a",8);
ngx.say("字符a的摸值是"..index);
local time = demo.time();
ngx.say("当前时间是"..time);
';
}
}
调用curl http://127.0.0.1/test 会输出相应的值
1.性能上的考虑,lua毕竟是一个脚本语言,对于某些特定的功能如果用纯lua来实现性能上一般都会比用c要逊色一些。
2.没有现成的库供我们使用,实际上互联网上已经有很多现成的第三方lua库供我们使用,比如读取redis数据的resty.redis;将json转化为lua本地数据格式的cjson等。当找不到合适我们使用的第三方库的时候,我们就需要自己动手了。当然如果能够直接使用lua来写一个满足我们自己使用的库也是可以的,如果考虑到性能问题,用c来实现是一个不错的选择。
我们这里打算实现两个方法
1.对一个字符串做hash并对其hash值取摸,在lua中我们可以这样调用该方法:
local value = demo.mod("abcdefe",8);
其中demo是我们写好的c库;
mod方法的第一个参数是要进行取摸的字符串;
第二个参数是摸;
2.由于lua中的时间函数无法精确到毫秒级,我们这里实现一个可以获取系统毫秒的时间:
local time = demo.time();
具体实现
首先引入lua的c api头文件和我们用到的时间头文件
#include <lua.h> #include <lauxlib.h> #include <lualib.h> #include <sys/time.h>
实现一个murmurhash算法,用来hash我们的字符串
typedef unsigned long long uint64_t;
typedef long long int64_t;
typedef long int int32_t;
static uint64_t murmurhash64A(const void *key,size_t len,int32_t seed){ int64_t m = 0xc6a4a7935bd1e995LL; int r = 47; uint64_t h = seed ^ (len * m); const uint64_t * data = (const uint64_t *)key; const uint64_t * end = data + (len >> 3); while(data != end){ uint64_t k = *data++; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; } const unsigned char * data2 = (const unsigned char *)data; switch(len & 7){ case 7: h ^= (uint64_t)data2[6] << 48; case 6: h ^= (uint64_t)data2[5] << 40; case 5: h ^= (uint64_t)data2[4] << 32; case 4: h ^= (uint64_t)data2[3] << 24; case 3: h ^= (uint64_t)data2[2] << 16; case 2: h ^= (uint64_t)data2[1] << 8; case 1: h ^= (uint64_t)data2[0]; h *= m; }; h ^= h >> r; h *= m; h ^= h >> r; return h; }
我们看到上面这个方法是一个纯c函数,lua如何于c传递数据呢?我们看下面这个方法
// 时间上lua和c交换数据使用的是一个lua_State栈结构 // 当我们在lua中调用demo.mod("a",8);这个方法时,该方法的两个参数会被顺序的压入到栈顶 // 这个时候栈底是字符串"a",栈顶是数字8 static int mod(lua_State *L){ //checks whether the key is a string size_t len; // 这个方法用来检查第一个参数是不是一个字符串或数字,如果不是那么lua在调用时就会报错 // len这个变量保存的是字符串的长度,这个值是调用该方法后被回填的值。 // 还有一个需要说明的是,在lua的栈中序号1代表栈底,序号2代表栈底的上一个元素 // 所以这里我们向luaL_checklstring方法的第二个参数传入1 const void *key = luaL_checklstring(L,1,&len); //checks if the num is a number int num = luaL_checknumber(L,2); uint64_t seed=0x1234ABCD; uint64_t h = murmurhash64A(key,len,seed); int index = h%num; // 将计算出的摸值压入栈顶 lua_pushnumber(L,index); //the first return value // 返回值代表demo.mod()这个方法返回的参数个数 // lua会根据返回数字的个数,从栈中逐个取出作为lua方法的返回值 return 1; }
好了,有拉上面mod方法的解释,我们获取系统时间的方法就比较容易理解了。
实现获取当前毫秒级的系统时间
static int currentTime(lua_State *l){ struct timeval time; int status = gettimeofday(&time,NULL); if(status < 0){ lua_pushinteger(l,-1); return 1; } int64_t millis = (int64_t)time.tv_sec * 1000 + (int64_t)time.tv_usec / 1000; lua_pushinteger(l,millis); return 1; }
接下来就是要讲我们写好的c函数注册到lua中了
方法格式: int luaopen_xxx(lua_State *L)
其它都是固定的,只有xxx使我们自定义的库名,我们这里给它起个名字叫demo
int luaopen_demo(lua_State *L){ //所有要注册到lua中的c函数放到luaL_Reg数组中 const luaL_Reg methods[] = { {"mod",mod}, {"time",currentTime}, {NULL,NULL} }; //注册c方法到lua //此时栈顶的值是demo // 创建栈结构 lua_newtable(L); // 这个方法使用lua5.2中摘抄过来的 // 把数组methods中所有的函数注册到栈顶的demo中,并指定upvalue的个数 // 因为我们这里没有用到upvalue值,所有传入0 setfuncs(L,methods,0); //向栈顶压入一个字符串代表我们的版本号 lua_pushliteral(L,"0.0.1"); //将栈顶的值赋值到,栈中第二个元素的version字段上,并将栈顶弹出 //demo.version=0.0.1 lua_setfield(L,-2,"version"); //返回栈顶的demo值 return 1; }
下面这个是我们从5.2中拿过来的代码
static void setfuncs (lua_State *l, const luaL_Reg *reg, int nup){ int i; luaL_checkstack(l, nup, "too many upvalues"); for (; reg->name != NULL; reg++) { /* fill the table with given functions */ for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(l, -nup); lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ lua_setfield(l, -(nup + 2), reg->name); } lua_pop(l, nup); /* remove upvalues */ }
实际上在lua5.1中使用lua_register()和luaL_register()等方法同样可以将c函数注册到lua中。
使用方法
将上面的代码编译成.so共享库
cc -c -O3 -Wall -pedantic -DNDEBUG -I/luajit/include/luajit-2.1 -fpic -g -o lua_demo.o lua_demo.c
cc -bundle -undefined dynamic_lookup -o demo.so lua_demo.o
/luajit/include/luajit-2.1 是luajit的头文件所在目录
lua_demo.c 是我们上面编写好的代码
将demo.so拷贝到一个指定目录,比如我们这里是/nginx/lualib
在nginx中像这样使用
lua_package_cpath "/nginx/lualib/?.so;;"; //注意是两个分号
server {
listen 80;
location ~ /test {
content_by_lua '
local demo = require "demo";
local index = demo.mod("a",8);
ngx.say("字符a的摸值是"..index);
local time = demo.time();
ngx.say("当前时间是"..time);
';
}
}
调用curl http://127.0.0.1/test 会输出相应的值
发表评论
-
模块化的ngx
2019-05-23 17:17 725提到ngx,一个永远绕不 ... -
写一个核心模块
2019-05-23 17:15 615在上一篇中有提到目前ngx共有六种模块,分别是: ... -
关于阶段
2019-03-01 07:59 575阶段一词来自于英文中的phase,对于刚接触nginx的同 ... -
双面if
2019-01-16 23:09 645在介绍nginx变量时 ... -
深入理解location匹配规则
2018-12-05 07:30 1605在前面几篇文章中,为了表述某个问题,我们都会举例说明,其中 ... -
nginx中的脚本(实战篇)
2018-10-22 22:50 2706上一篇基本以理论为主,介绍了ngx中脚本实现的基本要素,这 ... -
nginx中的脚本(理论篇)
2018-09-06 08:07 1043按照常规的打法或者 ... -
Nginx中变量的实现(上)
2018-06-22 07:07 1837上一篇主要描述的是 ... -
Nginx中变量的实现(下)
2018-06-22 06:56 1073这是Nginx中变量的实现 ... -
Nginx中的变量
2018-05-11 07:11 4327在计算机语言中,变量是用来存储和表示数据的,但不 ... -
Nginx系列文章-目录
2018-04-24 01:14 1019... -
Nginx模块开发(二)-内容阶段(NGX_HTTP_CONTENT_PHASE)
2015-11-03 18:08 135我们在编写自己的http模块的时候都需要注册一个handler ... -
C语言学习笔记
2015-10-10 23:25 115#一些工具 Valgrind : 用 ... -
我是如何构建高并发下响应式读服务的
2015-10-08 18:07 184一. 该系统的特点 该系统主要为商城全站提供数据读服 ... -
编写nginx模块一,hello模块
2015-07-09 14:45 727最近在阅读nginx源码,为了加深对nginx的理解,打算通过 ... -
Nginx学习
2012-12-28 18:47 0##安装Nginx 1.GCC---GNU编译器集合 g ...
相关推荐
1. **Nginx模块 ngx_lua**:Nginx与Lua的桥梁是ngx_lua模块,由OpenResty公司开发,它允许我们在Nginx配置文件中直接嵌入Lua脚本,实现动态处理请求。 2. **性能优势**:由于LuaJIT(Just-In-Time编译器)的存在,...
`lua`脚本可以直接嵌入到`nginx`配置中,允许我们在不重启服务器的情况下动态执行代码。例如,我们可以编写一个`lua`脚本来从请求头中提取`token`,然后使用`redis`进行验证。`lua`连接`redis`的库,如`lua-resty-...
- **Lua**:是一种轻量级的脚本语言,易于嵌入其他应用程序中。Lua的设计目标是为了提高效率与可扩展性,在游戏开发、网络应用等领域有着广泛的应用。 - **OpenResty**:是一个基于Nginx与Lua的高性能Web平台,它极...
- 直接在Nginx配置文件中嵌入Lua代码,简化配置管理。 - 支持异步非阻塞操作,保持Nginx的高性能。 - 提供丰富的Nginx变量和API,与Nginx内部机制紧密集成。 - 可以调用C库,扩展功能边界。 - 良好的错误处理机制和...
在 OpenResty 中,Lua 代码可以直接嵌入到 Nginx 的配置文件中,处理动态请求,如 URL 转发、会话管理、限流策略等。 Nginx 是一个高性能的反向代理服务器,擅长处理静态资源,如 HTML、CSS、JavaScript 文件。通过...
通过学习上述内容,开发者可以掌握在Nginx中集成Lua语言,使用OpenResty开发高性能的Web应用程序的技能。同时,通过具体的实战案例,可以加深对Nginx+Lua架构的理解,并能够将理论知识应用到实际开发中去。这种开发...
2. **Lua scripting in Nginx**: Nginx 的 ngx_lua 模块允许在 Nginx 配置中嵌入 Lua 代码,这样可以执行动态逻辑,比如数据处理、API 调用等。这增强了 Nginx 的功能,使其超越了传统的静态文件服务器角色。 3. **...
Lua-nginx-module是Nginx服务器的一个扩展模块,它允许我们在Nginx配置文件中直接嵌入 Lua 脚本,极大地增强了Nginx的功能性和灵活性。这个"lua-nginx-module-master.zip"压缩包包含了该模块的源代码,是安装和...
OpenResty是Nginx与Lua结合的典范,它是一个基于Nginx核心的完整Web应用程序框架,集成了LuaJIT(Lua的Just-In-Time编译器)以及一系列精心挑选的Nginx模块,如lua-nginx-module和ngx_http_lua_module,这些模块使得...
这个插件允许开发者在Nginx配置文件中嵌入Lua代码,实现更复杂的逻辑处理和功能增强,从而超越了传统静态配置文件的能力。版本0.9.14是该插件的一个特定版本,提供了对Lua脚本的稳定支持。 1. **Lua在Nginx中的应用...
- **易用性**:通过将Lua脚本直接嵌入到Nginx配置文件中,开发者可以轻松地实现业务逻辑的定制化处理。 #### 知识点三:Nginx+Lua 在京东的实际应用场景 - **具体场景**:京东内部多个业务系统采用了Nginx+Lua...
Lua模块是Nginx的一个扩展,允许在Nginx配置文件中嵌入Lua脚本,提供了更灵活的服务器配置和动态处理能力。在开发过程中,结合Nginx和Lua可以实现高效、轻量级的Web服务。 2. **安装Nginx** 安装Nginx需要先确保...
Lua-Nginx-Module是Nginx服务器中一个强大的扩展模块,允许我们在Nginx配置文件中直接嵌入Lua脚本,极大地提高了Nginx处理动态请求的能力。本文将详细探讨该模块的版本0.10.9rc7及其在实际使用中的关键知识点。 ...
Lua-Nginx 模块是将 Lua 脚本语言集成到 Nginx Web 服务器中的一个强大插件。在标题 "lua-nginx-16" 中提到的是该模块的一个特定版本,即 0.9.16。这个版本可能包含了针对性能优化、功能增强或者错误修复的更新。...
Lua是一种轻量级的脚本语言,被广泛用于嵌入到其他应用程序中,提供动态扩展和自定义逻辑。在Nginx环境中,我们可以使用`ngx_lua`模块(也称为OpenResty)来运行Lua代码,实现服务器端的业务逻辑。Lua脚本(如`yup....
Nginx的Lua模块(lua-nginx-module)允许我们在Nginx配置文件中直接嵌入Lua代码,实现动态处理请求和响应,这极大地提高了灵活性和可编程性。 为了整合Nginx与Redis,我们还需要几个Nginx的第三方模块: 1. `lua-...
Nginx 是一款高性能的 HTTP 和反向代理 Web 服务器,而 ngx_lua 模块则是 Nginx 的一个强大扩展,它允许在 Nginx 中直接嵌入 Lua 脚本进行动态内容处理和请求/响应的修改。这种集成不仅提高了 Nginx 的灵活性,还极...
从提供的文件内容来看,这是一份关于Nginx结合Lua编程的实用手册,主要介绍了如何将Lua脚本语言嵌入到Nginx HTTP服务中,从而提升其性能和功能。这份手册详细介绍了ngx_http_lua_module模块的安装、使用以及在Nginx...
OpenResty将Lua嵌入到Nginx中,使得开发者可以在Nginx的配置文件中直接使用Lua脚本语言,这为Nginx提供了强大的动态脚本能力和更灵活的业务逻辑处理。 将Lua集成到Nginx中,可以将Nginx的静态功能动态化,支持复杂...
在这个场景下,"nginx+lua+redis黑名单加载"的组合通常用于实现一种安全策略,即通过`nginx`拦截并阻止某些IP或用户访问,这些IP或用户在`redis`中被标记为黑名单。 **1. nginx作为前端代理:** `nginx`是一个高...