一, 引言
学习 Redis 也有一段时间了, 感触还是颇多的, 但是自己很清楚, 路还很长, 还要继续. 上一篇文章简要的介绍了如何在 Linux 环境下安装 Lua, 并介绍了在 Linux 环境下如何编写 Lua 脚本和运行. 由于我们这个系列是以 Redis 为主, 所以也介绍了 Redis 和 Lua 如何进行整合, 运行.
在 Lua 脚本中有一个很重要的数据类型, 那就是 table 类型, 大家可以把 Lua 的 table 类型暂时理解为数组, 只是 Lua 的 table 类型的下标可以是数字, 可以是字符, 除了 (nil) 类型, 其他类型都可以做为 table 类型的下标. 我们在使用 Redis 和 Lua 的过程中, 比较多的会用到这个 table 类型, 今天的主要任务就是介绍 table 类型的使用, CJSON 的解析和如何通过 C# 语言来对 Redis 和 Lua 的进行整合操作. 后续我还会推出针对 Lua 脚本语法的文章来扩充这个系列.
二, Lua 简介
Lua 是一个小巧的脚本语言. 其设计目的是为了嵌入应用程序中, 从而为应用程序提供灵活的扩展和定制功能. Lua 由标准 C 编写而成, 几乎在所有操作系统和平台上都可以编译, 运行. Lua 并没有提供强大的库, 这是由它的定位决定的. 所以 Lua 不适合作为开发独立应用程序的语言.
在 Redis 中使用 Lua 有很多好处, 它可以减少网络开销, 把多个操作一次性打包执行. Lua 脚本天生支持原子性的操作, 避免开启第三方事务, 提高了性能. 代码重用也是一个重要的好处, 写好的代码会被加载到 Redis 内存中, 可以供其他客户端使用, 减少重复劳动. Lua 脚本使用 C 语言写成的, 执行速度很快, 并天然具有可移植性, 也是代码重用的很好体现. 一个完整的 Lua 解释器, 不过 200k, 在目前所有脚本引擎中, Lua 的速度是最快的. 这一切都决定了 Lua 是作为嵌入式脚本的最佳选择.
三, 基本操作
1, 在 Linux 环境下安装 CJSON 和简单使用
cjson 是一个类型转换工具类, 可以把一个字符串转换为 Lua 的类型, 如果类型嵌套多层, 还可以转换为 Lua 的 table 类型, 所以这个工具很重要, 在编写 Lua 脚本的过程中经常使用, 所以我们先来介绍 cjson 这个工具类的安装和使用.
1.1, 下载 CJSON 软件包, 官网地址: https://www.kyne.com.au/~mark/software/lua-cjson.php.
[root@linux cjson]# pwd
/root/software/download/cjson
[root@linux cjson]# wget https://www.kyne.com.au/~mark/software/download/lua-cjson-2.1.0.tar.gz
1.2, 解压到当前目录, 当然也可以解压到其他目录, 解压到其他目录, 比如:/usr/local, 命令如下: tar zxvf lua-cjson-2.1.0.tar.gz -C(大写的) /usr/local
// 当前目录
[root@linux cjson]# pwd
/root/software/download/cjson
// 显示当前目录下的文件和目录
[root@linux cjson]# ls
lua-cjson-2.1.0.tar.gz
// 解压到当前目录
[root@linux cjson]# tar zxvf lua-cjson-2.1.0.tar.gz [-C /usr/local]
//...
complete!
解压成功后的目录结构:
1.3, 进入到解压目录的根目录, 准备修改 Makefile 文件, 用 vim 打开的修改文件的时候, 注意名称大小写拼写正确.
// 当前目录
[root@linux cjson]# pwd
/root/software/download/cjson
// 进入到 CJSON 的解压根目录
[root@linux cjson]# cd lua-cjson-2.1.0
// 进入到根目录, 修改 Makefile 文件
[root@linux lua-cjson-2.1.0]# vim Makefile
1,4,vim 进入 Makefile 文件, 修改 PREFIX 选项, 修改完毕, 按 ESC 按钮, 再按:, 最后按 wq, 保存退出.
// 当前目录
[root@linux lua-cjson-2.1.0]# pwd
/root/software/download/cjson/lua-cjson-2.1.0
1.5, 使用 make 命令在解压文件的根目录下进行编译.
// 当前目录
[root@linux lua-cjson-2.1.0]# pwd
/root/software/download/cjson/lua-cjson-2.1.0
[root@linux lua-cjson-2.1.0]# make
// 开始编译
1.6, 最后使用 make install 安装 cjson 软件包.
// 当前目录
[root@linux lua-cjson-2.1.0]# pwd
/root/software/download/cjson/lua-cjson-2.1.0
[root@linux lua-cjson-2.1.0]# make install
// 开始安装
1.7,cjson.so 文件很重要, 是核心运行文件, 如果出现错误, 在某某目录没有找到 cjson 这个文件, 就在其他目录找到, 并拷贝到目标目录, 可以解决所出现的错误.
[root@linux program]# pwd
/root/application/program
// 拷贝 sjson.so 文件到指定目录
[root@linux program]# sudo cp -r cjson/lib/lua/5.1/cjson.so /usr/local/lib/lua/5.3
错误如图:
只需要把 cjson.so 文件拷贝到[/usr/local/lib/lua/5.3(这个版本具体情况要看具体情况)/] 目录下就可以了
1.8, 安装完成, 开始测试 cjson 安装是否成功, 此步骤有两步, 必须全部都完成.
//1, 从 Linux 命令行模式进入 lua 命令行测试安装是否正确
[root@linux lua-cjson-2.1.0]# lua
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org PUC-Rio
>local cjson=require("cjson")
>local cjson2=require "cjson.safe"
// 以上所有操作没有提示任何错误
//2, 我们在 Linux 命令行下在执行 lua 命令, 执行 lua 脚本, 测试是否安装成功
//05.lua 脚本文件的源码
local cjson=require "cjson"
local smapleJson=[[{"age":"23","testArray":{"array":[8,9,1,14,15]},"baidu":"www.baidu.com"}]];
local data=cjson.decode(sampleJson)
print(data["age"]);
print(data["testArray"]["array"][1])
// 没有提示任何错误, 安装成功
// 在 Linux 环境下执行刚才的 Lua 脚本
[root@linux lua-cjson-2.1.0]# lua /root/application/program/luascript/05.lua
23
8.0
// 安装成功
2, 在 Linux 环境下, 在 Lua 脚本里面使用 cjson 来解析类型.
//cjsonDemo.lua 的源代码如下:
local cjson = require "cjson"
local retTable = {}; -- 最终产生 json 的表
-- 顺序数值
local intDatas = {};
intDatas[1] = 100;
intDatas[2] = "100";
-- 数组
local aryDatas = {};
aryDatas[1] = {};
aryDatas[1]["键 11"] = "值 11";
aryDatas[1]["键 12"] = "值 12";
aryDatas[2] = {};
aryDatas[2]["键 21"] = "值 21";
aryDatas[2]["键 22"] = "值 22";
-- 对 Table 赋值
retTable["键 1"] = "值 1";
retTable[2] = 123;
retTable["int_datas"] = intDatas;
retTable["aryDatas"] = aryDatas;
-- 将表数据编码成 json 字符串
local jsonStr = cjson.encode(retTable);
print(jsonStr);
return retTable;
// 以上为 Lua 源码
// 开始执行命令
[root@linux luascript]# pwd
/root/application/program/luascript //lua 脚本存放的位置
[root@linux luascript]# lua cjsonDemo.lua
{"int_datas":[100,"100"],"2":123,"键 1":"值 1","aryDatas":[{"键 12":"值 12","键 11":"值 11"},{"键 21":"值 21","键 22":"值 22"}]}
执行效果如图:
3, 在 Windows 环境下, 用 C# 执行 lua 脚本
3.1, 在 VS2015 中建一个 C# 控制台应用程序, 并添加 LuaInterface.dll 的引用
LuaInterface 下载地址: http://luaforge.net/projects/luainterface/ (下载 luainterface-1.5.3, 这里面的资源比较多)
LuaInterface.Lua 类是 CLR 访问 Lua 解释器的主要接口, 一个 LuaInterface.Lua 类对象就代表了一个 Lua 解释器(或 Lua 执行环境),Lua 解释器可以同时存在多个, 并且它们之间是完全相互独立的.
3.2, 在 Windows 环境下, Lua 脚本文件使用上面提到的源文件 cjsonDemo.lua.
文件所在地址如下: C:\Users\Administrator\Desktop\Redis\LuaScript\cjsonDemo.lua
// 源码如下:
local retTable = {}; -- 最终产生 json 的表
-- 顺序数值
local intDatas = {};
intDatas[1] = 100;
intDatas[2] = "100";
-- 数组
local aryDatas = {};
aryDatas[1] = {};
aryDatas[1]["键 11"] = "值 11";
aryDatas[1]["键 12"] = "值 12";
aryDatas[2] = {};
aryDatas[2]["键 21"] = "值 21";
aryDatas[2]["键 22"] = "值 22";
-- 对 Table 赋值
retTable["键 1"] = "值 1";
retTable[2] = 123;
retTable["int_datas"] = intDatas;
retTable["aryDatas"] = aryDatas;
return retTable;
3.3, 测试代码如下:
using LuaInterface; // 引入的 dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CSharpPinvokeLuaDemo
{
class Program
{
static void Main(string[] args)
{
// 新建一个 Lua 解释器, 每一个 Lua 实例都相互独立, 一个 global 全局域
Lua lua = new Lua();
//---------------------------------------------------
// Lua 的索引操作 [] 可以创建, 访问, 修改 global 域
lua["age"] = 20;
lua["name"] = "Mr.huang";
string luaCode = "print(\"This is Lua code\")";
lua.DoString(luaCode);// 执行 lua 脚本代码
object[] result=lua.DoFile(@"C:\Users\Administrator\Desktop\Redis\LuaScript\cjsonDemo.lua");// 执行 lua 脚本文件, 这里我直接用了绝对定位
double age = (double)lua["age"];
Console.WriteLine("age = {0}", age);
Console.WriteLine("width = {0}", lua["width"]);
Console.ReadKey();
}
}
}
3.4, 有可能抛出的异常: FileLoadException, 异常内容: 其他信息: 混合模式程序集是针对 "v2.0.50727" 版的运行时生成的, 在没有配置其他信息的情况下, 无法在 4.0 运行时中加载该程序集.
该问题解决不是很难, 只要在配置文件里增加一点配置就能解决. 配置代码如下:
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
<supportedRuntime version="v2.0.50727"/>
</startup>
在原来. NET2.0,.NET3.5 的时候, 由于程序运行环境本质还是. NET2.0, 而到了. NET4.0 由于整个程序集的版本更新, 以前使用. NET2.0 所编写的程序集与. NET4.0 的程序集继续互操作的时候就会出现上面所说的兼容性问题. 通过 MSDN, 我们可以知道, startup 配置节中的 useLegacyV2RuntimeActivationPolicy 属性是在. NET4.0 中新增的, 默认是 false, 表示: 使用默认的 .NET Framework 4 激活策略, 该激活策略将加载 .NET Framework 4 通过使用公共语言运行时 (CLR) 版本 4 所创建的程序集, 以及 CLR 早期版本通过使用受支持的低于版本 4 的最高 CLR 版本所创建的程序集.
现在如果当程序在. NET4.0 环境下要使用. NET2.0 及. NET3.5 的程序时就必须将 useLegacyV2RuntimeActivationPolicy 设置为 true, 同时还要注意, 需要在 startup 配置节的字节中添加 supportedRuntime 配置节, 并指定为 "v4.0", 表示使用. NET4.0 运行时来运行程序.
四, 结束
今天就写到这里了, 就给今天做一个总结吧. 今天主要完成了 lua-cjson 在 Linux 下的安装和使用, 当然也有出现问题的解决. 同时也测试了在 Linux 环境下, 在 Lua 脚本中使用 cjson 工具类完成 table 类型的解析. 最后也测试了一下如何使用 C# 来调用 lua 脚本, 并执行. 但是有一个事情, 还没做, 就是在 Windows 环境下, 如何在 Lua 脚本里使用 lua-cjson 来解析类型, 里面涉及到的内容很多, 一篇文章无法写完, 只好把相关的东西放到下一片文章吧.
来源: https://www.cnblogs.com/PatrickLiu/p/8405781.html