存档

  • Lua C++ bindings (2)

    这是关于 lua-cpp 的第二篇博客,上一篇在 这里。这里主要是根据 git 的提交日志回忆一下实现过程,有点意识流,想到哪说那了。btw,代码在 这里

    设置和获取变量

    首先是一般的变量的获取。返回数值比较好办,字符串也可以返回 std::string,但是像 table 和函数这样的类型就不好直接返回了。一个直接的想法就是在外面封装一层,记下 lua_State 和对应的位置。刚开始就是直接记的栈内的 index,但是当某个对象析构之后在这个对象之后创建的对象的 index 都要改变,因此这个方法行不通。后来翻 API 的时候发现可以用 luaL_ref() 和 luaL_unref(),问题就解决了。

    一个不算太重要但是也比较基础的问题是这些类型的生存期问题,其实也就是 lua_State 的作用域问题。Lua 本来就要求使用者自己保证,但是这个保证有函数调用来强制(Lua 的函数都需要提供 lua_State),如果封装成 C++ 后每个函数都要求传入 LuaState 就太不专业了,于是想到在每个类里加一个 std::shared_ptr,然后判断引用计数来决定是否析构;后来在查手册的时候发现 shared_ptr 居然还支持自定义析构函数,而 lua_close() 正好符合要求的析构函数形式,这样

    阅读全文…

    2015年3月8日 | 归档: 软件开发 | 标签:
  • 使用 Lua 扩展你的程序 (1)

    Lua(参考资料[1])是巴西里约热内卢天主教大学的一个研究小组于 1993 年开发的。小组主要由 Roberto Ierusalimschy, Waldemar Celes 和 Luiz Henrique de Figueiredo 组成,最开始的原型为了处理数据而开发的一种脚本语言,后来逐渐演变成现在的样子。Lua 虽然小巧,但是也包含分支循环结构,动态类型,闭包等特性,有兴趣的可以看看参考资料[2]。只用 Lua 提供的原生 C API 写出来的程序和汇编差不多,需要精确控制栈的内容。为了解放程序员,网上有一些封装好了的 Lua 库,用起来也很方便。

    这里主要记录自己使用 Lua 对程序进行扩展的一些尝试,用到相关的 Lua 特性时会展开介绍一下。特别说一下,虽然主要使用 Lua 作为配置文件的语言,但是用其它的语言(Python, Perl, Ruby, …)也可以达到同样的效果,只要程序能够解析所使用的语言,甚至 XML 也可以用来实现后文提到的一些功能,不过前提是你的解析器要支持 XML 来定义分支和循环等功能 :)

    简单的 key/value 配置文件

    需要配置参数取值的一个常见例子是数据源问题。例如程序需要从一个文件获取运行时需要的数据,测试和正式发布所使用的数据不一样,为了验证程序的正确性也准备了多套不同的数据。为了方便测试,程序使用了一个配置文件 …

    阅读全文…

    2014年7月24日 | 归档: 软件开发 | 标签:
  • 项目总结 (2)

    很累的一个月,为了赶项目天天码代码,第一次在看到代码的时候有想吐的感觉。

    用 lua 作为配置文件

    因为在之前的一个项目中师兄采用了网络作为前后端交互的方式,这样两部分分开调试比较方便,从此以后实验室的项目不管是否需要联网都采用这种方法,结果在项目中除了根据甲方的需求把控件拖来拖去之外剩下的就是解析各种各样的报文格式。

    前段时间另一个项目需要写一个报文测试的小工具,就是有一堆自定义的报文格式,界面上有下拉条选择或者让用户自己输入某个字段的值,然后把报文发出去,收到返回信息并且把内容解析一下。我已经不怎么碰这个项目了,但是这次时间有点紧,于是哥又“被”当仁不让地充当临时工把活接了下来。在前一个项目中师兄使用了 xml 作为报文格式配置文件,这个小工具我打算用 lua 来试一下,也算是一个实际应用的机会。界面用了 qt,因为现在 qt 俨然成为本人实验室项目界面开发的默认工具了。

    先说说使用 lua 作为配置文件吧。报文格式是常见的 TLV 格式(“T”表示 type,“L”表示长度,“V”表示数据),有些字段会有限定的范围:

    packet = {
        "报文名称",
        {"字段名称1", "字段类型", 个数, {可选值1, "说明1"}, {可选值2}, {起始值, 结束值, 步长}, ...},
        ......
    }
    

    其中字段类型定义了一些常见的类型并规定了长度,例如“int”就是 4 字节,“double”就是 8 个字节等。个数表示该字段中包含了多少个这样的类型。例如…

    阅读全文…

    2012年6月3日 | 归档: 软件开发 | 标签: , ,
  • c 语言实现封装,继承和多态

    封装

    c 语言使用的 struct 没有访问控制,任何程序都能访问 struct 的成员。为了隐藏 struct 里的成员名称和位置,可以将具体的 struct 定义放在 .c 文件中,而在头文件中增加一个指向该结构体的指针。因为无法得知指针类型的具体定义,对这个私有结构体成员的访问只能通过提供的 set() 和 get() 函数。

    下面是头文件 test.h 的定义:

    #ifndef __TEST_H__
    #define __TEST_H__
    
    struct test {
        struct _test* t;
    };
    
    int test_constructor(struct test*);
    int test_get(struct test*);
    void test_set(struct test*, 

    阅读全文…

    2012年4月3日 | 归档: 软件开发 | 标签:
  • 项目总结 (1)

    年前开始做这个项目,虽然主要的功能放假前已经完成,但是老板为了体现实验室的主题——并行计算,要求把一个简单的 hash 查找功能弄成复杂的“多线程并行计算”,尽管最后的多线程实现比串行的还慢(通过使用 gprof 分析发现花在同步上的开销超过了多线程带来的并行效益,因为实际的 hash 查找不怎么耗时间)。当然这些我是无力改变的,不过有个好处就是老板虽然不懂具体技术,但是却不会瞎指挥,所以在实现上倒是挺自由的,因此可以随便尝试自己想学的东西,只要最后项目完成就行。

    好了,发完牢骚之后总结一下从中学到的东西吧。

    生产者-消费者问题

    我觉得所有的问题基本都可以归结为生产者-消费者问题:输入是生产者,程序处理是消费者。刚开始写的是串行的代码,使用惯用的套路:

    int main(void)
    {
        ......
    
        while ((rec = producer()))
            consumer(rec);
    
        ......
    }
    

    串行程序需要由 main() 函数驱动,主要逻辑由 main() 函数搭建,这样的话如果非要把多线程嵌到这个模型中,看起来会有点奇怪:

    void* producer(void)
    {
        /* blcok until data arrives */
        return get_resource_from(resource_pool);
    }
    
    void consumer(void* 

    阅读全文…

    2012年3月3日 | 归档: 软件开发 | 标签:
  • 使用 libpcap 分析网络报文 (2)

    这里打算写写报文分析接口的设计。 一般来说,以太网的报文格式为:

    +------------+-------------------+-----+
    | eth header | ip/arp/... header | ... |
    +------------+-------------------+-----+
    

    例如手机上的一次网页请求的报文格式可能像下面这样:

    +-----+----+-----+-----+----+-----+--------------+
    | eth | ip | udp | gtp | ip | tcp | http request |
    +-----+----+-----+-----+----+-----+--------------+
    

    不同的应用对于不同协议的内容可能会有不同的需求。比方说,一个应用希望抓取 gtp 报头中的 pdp context,以此建立起某个手机号在某段时间内使用的是哪个 ip 的映射,它不关心上层应用的内容;另一个应用希望抓取内层 ip …

    阅读全文…

    2011年10月1日 | 归档: 软件开发 | 标签:
‘软件开发’ 分类的存档