Lua 在.net 中的是非(研究的人似乎不多)

来源:互联网 发布:网络奇兵2游侠 编辑:程序博客网 时间:2024/05/09 10:48

很久没上博客了,换了工作之后一直忙的不可开交,我也自认个人能力比较有限,但无奈的是很多事情都从技术层面上压迫自己,整那些压根就没接触过或不熟悉的东西,。
  
   不过还是能学到不少东西,关于Lua,应该说我是从新魔界游戏才了解的,当时我以为是金酷自己的发明的一种脚本,真是固陋寡闻呀!不是因为技术考虑上需要,我也懒的去研究,原来这个东西是巴西的一个家伙发明的,原本作为C的扩展,最后到成了游戏里吃香的馍馍,包括WOW(本人并不喜欢)居然可以让玩家自己通过LUA脚本来定制客户端,强捍。
  
   到网上一查,嘿嘿,关于LUA的东西到不少,名气还是很大的,至少很多游戏都首选LUA作为脚本引擎,LUA作为纯ANSI C实现的轻量级的虚拟机,且结构简单,优美,额!我才不管它多优美了,不过现在的确是有求于它,主要是由于客户需要能够按它们要求去抓取网页数据并能形成所期望格式的表,这下可为难我了,我没有研究过蜘蛛,只是了解,但我肯定网上找不到一个适合我的,至少我们的客户不是只有一个有这种需要,这对于维护实在是太麻烦,我倒是可以根据你的要求去取网页,分析网页数据,抓取特定部位存,但客户的抓取需求非常多,而且如果人家网站变了,你的重新修改程序,编译发布,工作量可想而知,重要的是,全国有很多远的客户,那个维护就更是麻烦,人都会被整崩溃,于是LUA进入我得视野,我本想自己实现一个简单的,可以通过配置抓取模板来处理网页数据的抓取(这里页面数据的某些抓取部分肯定需要复杂的提取逻辑,程序里写死肯定不好),但想想,自己写反编译器却最终半徒而废,这个由于工作还是可以硬头皮实现,但这种临时拼凑的东西合适吗,估计你要保证稳定工作都要不短的时间,还得功能够强,埃,郁闷死个人。
  
   于是就到处搜索LUA的.NET应用,不过真是可惜,除了LUA自己的一个PDF编程指南外,基于.NET下的LUA的丰富应用的资料还真是少的可怜,就连我寄希望的博客园里搜索也没有找到几篇文章,搜到就一个LUAINTERFACE,这个东西的确让我们搞.NET的对LUA应用作出了贡献,不过网上说什么有一个多核的BUG,会崩溃,虚拟机,那个家伙实在不够意思,给个修改版本的连接居然下不了,对问题的修改地方也一个字都不提,我想,大不了我要求客户机器是单核CPU的不就玩了,耶! LUAINTERFACE并不是LUA虚拟机本身,它是对LUA的一层接口封装,你的有一个LUA的托管C++编译版本的DLL才行,还得有几个C++的运行期文件COPY在一起才能运行。
  
   这个接口,我倒是没有直接用,跑到CODEPLEX里搜到了一个LUANET,还不错,看看DEMO,还是很激动的,居然可以将.NET的类,方法注册到LUA虚拟机里,来扩展LUA虚拟机的API,这个不正是我想要得吗?一个虚拟机引擎,加一堆我针对网页提取,分析的粒子接口,利用LUA脚本来实现抓取模本配置,这样就可以很灵活的针对网页抓取的任务了,后面连程序都不该了,直接发一个XML的抓取模板就可以应付变化,而且可以随意修改,还有我作的一个简陋的智能表单框架,如果加入LUA引擎,岂不威力大增,
  
   不过我在写脚本IDE(简单的^_^)时,调试脚本居然发现,狗日的对中文字符串参数报脚本语法错误,那个郁闷都不知道从那里说去,毕竟俺分析的可以中文网页呀,这该死的ANSI,就没考虑过中国人的感受,郁闷了2天,GOOGLE,BAIDU都翻偏了,由于LUA.NET应用的不多,这个BUG居然没有人提出来,头脑一热,想,干脆自己把LUA的C代码读懂,改为纯C#实现的,这样多好呀,我连名字都想好了,就叫SHARPLUA^_^,不过时程问题,公司可不允许我有足够的时间来改写一个C#版本的虚拟机,如果能解决这个问题多好呀,没法,只有自己调试LUAINTERFACE了,发现到.NET这层的结构没有办法找错误,毕竟人家报的是脚本语法错误,也就是说这个执行已经进入到LUA虚拟机部分的代码了,那部分是C++的,埃,我C++是个半飘水,不熟悉(还是有些基础,自认为C还是整的不错的),找到LUAINTERFACE的开源下载,里面的LUA511就包含了LUA的C实现代码,工程都整了好久,直接下的需要调整编译器设置才能下,跟踪了N久,确认了数个函数后,终于发现可以的导致对中文处理上的代码,我靠,这个不知道算不算是错误,如果LUA是存C++非托管编译的(这个指LUA5。1。4的原始C开源版本),编译后,居然一点问题都没有,但是到.NET里用/CLR编译程托管版本就报这个错误,无语了。比如
  
   LUA5.1.4 VS2005 C++编译 非托管
  
  运行图如下
  
  一点错误都没有,汗
  
  但是.NET下 里死活报一个什么 没有结束的字符串的脚本语法错误,
  
  如果用print('jakskdjfjaf');非中文的话,就一点问题都没有
  
  不管是调用PRINT这个LUA虚礼机内置API出问题,包括所有你定义的变量的中文字符串,或是函数的参数,都无疑例外的出现脚本错误,
  
   最后跟踪C++的代码到了这里 是LUAXLIB.C 里的如下代码
  
  typedef struct LoadS {
   const char *s;
   size_t size;
  } LoadS;
  
  
  static const char *getS (lua_State *L, void *ud, size_t *size) {
   LoadS *ls = (LoadS *)ud; // 这里的*ud是有LUA经过词法解析后放在的作为字符串表达式的一个内存地址
   (void)L;
   if (ls->size == 0) return NULL; // *size到搞什么的,它是存放子串表达式长度的地址 一个int *指针参数
   *size = ls->size; // 比较看了看这里的代码核5.1.4里一模一样,但就是非托管C++里可以,托管的编译就不行
   ls->size = 0;
   return ls->s;
  }
  
  跟踪这里后,我反复看了看,终于发现问题之所在,比如声明一个 表达式 msg='我爱'; 这个语句,LUA这里这
  
  (LoadS *)ud 得到的结构里,长度居然是 9 ,由于C的CHAR是8位的, 很明显中文占2个字节,实际的字节数应该是11才对,就是这个小问题导致LUA语法解析 根据9长度取表达式,刚好取到 ‘爱’字,后面的 ’;2个字符给搞丢了,弄的是自己语法检查就来个 没有结束的字符串表达式,我想这里的(LoadS *) ud没有正确识别字符串的长度,还是有点鄙视LUA的作者的,写个不安全的代码,它应该用系统的strlen函数来完成,嘿嘿,根据我自己的想法,我修改了这段C代码,
  
  static const char *getS (lua_State *L, void *ud, size_t *size) {
   LoadS *ls = (LoadS *)ud;
   (void)L;
   if (ls->size == 0)
   {
   return NULL;
   }
   else
   {
   ls->size=strlen(ls->s); // 修改的地方
   }
   *size = ls->size;
   ls->size = 0;
   return ls->s;
  }
  NND ,问题终于解决了,终于可以心安的用LUA了,觉得LUA实在是好东西,如果你需要一个脚本引擎嵌入到你的C#应用中,玩LUA吧,的确是个好东西,一个可嵌入的脚本引擎,毕竟是开源且免费的。
  
   这篇随笔做抛石头引玉,LUA的.NET 的应用的确不多,有人想搞SHARPLUA的纯C#版本的虚拟机,我就享受成果吧^_^,最后有知道修改LUAINTERFACE多核CPU上的锁的朋友,可以给我留言(就留修改的地方核代码)

 

http://www.webkey.cn/code/view.asp?id=7323