当前位置: 首页 >> 网络协议与安全 >> 开源的SIP协议库PJSIP
 

开源的SIP协议库PJSIP

作者:      来源:zz     发表时间:2008-06-12     浏览次数:      字号:    


总算是初步列举完了PJLIB的基本特征了,后面我们来说说它的使用与实现:

4. PJLIB的使用

有了上述介绍,是不是很想知道这个库的使用,没关系,我们慢慢说来:)

首先是头文件和编译出来的库的位置,这就不必多说了,除非你没有使用过手动编译的库
,如果不太了解步骤,google一下,啊:)

1).为了使用这个库,需要使用:
#include <pjlib.h>
当然,也可以选择:
#include <pj/log.h>
    #include <pj/os.h>
    这种分离的方式,不过,简介其间,还是使用第一种吧:),毕竟,你不需要确认到你所
需的函数或者数据结构具体到哪个具体的头文件:)
   
    2).确保在使用PJLIB之前调用 pj_init()来完成PJLIB库使用前说必须的一些初始化.

    这是一个必不可少的步骤.
    ~~~~~~~~~~~~~~~~~~~~~~~
   
    3).使用PJLIB的一些建议
    作者对使用PJLIB的程序提出了一些建议,包括如下 :
    a).不要使用ANSI C[Do NOT Use ANSI C]
    观点很明确,ANSI C并不会让程序具有最大的移植性,应该使用PJSIP库所提供的响
应机制来实现你所需要的功能.
   
    b).使用pj_str_t取代C风格的字符串[Use pj_str_t instead of C Strings]
    原因之一是移植性,之二则是PJLIB内置的pj_str_t相关操作会更快(性能).
   
    c).从内存池分配内存[Use Pool for Memory Allocations]
    这很明显,如果你知道为什么会使用内存池的话(提示一下,性能以及易用性:))
   
    d).使用PJLIB的LOG机制做文字显示[Use Logging for Text Display]
    很明显:)
   
     还有些关于移植的一些问题,不在我们的讨论范围,如果你需要移植到其它平台或者
环境,请参考http://www.pjsip.org/pjlib/docs/html/porting_pjlib_pg.htm

5. PJLIB的使用以及原理
终于开始提及实现原理以及具体的编码了:),前面的列举还真是个琐碎的事情,还是奔主题
来:).

5.1快速内存池[Fast Memory Pool]
前面说过,使用内存池的原因在于性能的考虑,原因是C风格的malloc()以及C++风格的new
操作在高性能或实时条件下表现并不太好,原因在于性能的瓶颈在于内存碎片问题.

下面列举其优点与需要主要的问题:
优点:
a).不像其它内存池,允许分配不同尺寸的chunks.
b).快速.
内存chunks拥有O(1)的复杂度,并且操作仅仅是指针的算术运算,其间不需要使用锁住任
何互斥量.
c).有效使用内存.
除了可能因为内存对齐的原因会浪费很少的内存外,内存的使用效率非常高.
d).可预防内存泄漏.
在C/C++程序中如果出现内存泄漏问题,其查找过程哪个艰辛,不足为外人道也:(
[曾经有次用别人的Code,出现了内存泄漏,在开发板上查找N天,又没工具可在开发板上使
用,哪个痛苦,想自杀:(]
原因很简单,你的内存都是从内存池中获取的,就算你没有释放你获取的内存,只要你记得
把内存池destroy,那么内存还是会还给系统.

还有设计带来的一些其它益处,比如可用性和灵活性:
e).内存泄漏更容易被跟踪.
这是因为你的内存是在指定的内存池中分配的,只要能很快定位到内存池,内存泄漏的侦
测就方便多了.
f).设计上从内存池中获取内存这一操作是非线程安全的.
原因是设计者认为内存池被上层对象所拥有,线程安全应该由上层对象去保证,这样的话
,没有锁的问题会让内存分配变得非常的快.
g).内存池的行为像C++中的new的行为,当内存池获取内存chunks会抛出PJ_NO_MEMORY_EX
CEPTION异常,当然,因为支持异常处理,也可以使用其它方式让上层程序灵活的定义异常的
处理.
[这是异常处理的基本出发点,但是这有大量的争论,原因是这改变了程序的正常流程,谁能
去保证这种流程是用户所需要的呢,因此C++中的异常处理饱受争议,请酌情使用]
h). 可以在后端使用任何的内存分配器.默认情况下是使用malloc/free管理内存池的块,
但是应用程序也可以指定自己的策略(strategy),例如从一个全局存储空间分配内存.

恩,要知道,任何事务都是两面的(颇为佩服创造出“双赢”这个词的语言天才, 不过,文
字游戏对于技术人员不能说是件好事情:(),好了,使用时,不要认为这个内存池是哪种"per
fect"的技术,要记得"任何设计,都是在各种限制条件中的一个折中,对于'戴着镣铐的舞蹈
',除了'舞蹈',也不要忘记'镣铐'哦",不要忘了告诫:):
告诫[Caveats]:
a).使用合适的大小来初始化内存池.
使用内存池时,需要指定一个初始内存池大小, 这个值是内存池的初始值,如果你想要高
性能,要谨慎选择这个值哦,太大的化会浪费内存,过小又会让内存池自身频繁的去增加内存
,显然这两种情况都不可取.
b). 注意,内存池只能增加,而不能被缩小(shrink),因为内存池没有函数把内存chunks释
放还给系统,这就要去内存池的构造者和使用者明确使用内存.

恩,基本的原理都差不多了,后面我们来看看如何使用这个内存池.

5.2内存池的使用[Using Memory Pool]
内存池的使用相当的简单,扳个手指头就搞定了,如果你看明白了上面的原理和特征:)

a).创建内存池工厂[Create Pool Factory]
上面不是提及内存池的内部分配策略以及异常处理方式么, 其实这就是指定这个的:)

当然,不需要你每个内存池都自己取指定策略和异常处理方式,PJLIB已经有了一个默认的
实现:Caching Pool Factory,这个内存池工厂的初始化使用函数pj_caching_pool_init()


b).创建内存池[Create The Pool]
使用pj_pool_create(),其参数分别为内存工厂(Pool Factory),内存池的名字(name),初
始时的大小以及增长时的大小.

c).根据需要分配内存[Allocate Memory as Required]
然后,你就可以使用pj_pool_alloc(), pj_pool_calloc(), 或pj_pool_zalloc()从指定
的内存池根据需要去获取内存了:)

d).Destroy内存池[Destroy the Pool]
这实际上是把预分配的内存还给系统.

e).Destroy内存池工厂[Destroy the Pool Factory]
这没什么好说的.

很简单吧:)
作者在文档中给出了一个例子:
如下:
#include <pjlib.h>

   #define THIS_FILE    "pool_sample.c"

   static void my_perror(const char *title, pj_status_t status)
   {
        char errmsg[PJ_ERR_MSG_SIZE];

        pj_strerror(status, errmsg, sizeof(errmsg));
        PJ_LOG(1,(THIS_FILE, "%s: %s [status=%d]", title, errmsg, status));
   }

   static void pool_demo_1(pj_pool_factory *pfactory)
   {
        unsigned i;
        pj_pool_t *pool;

        // Must create pool before we can allocate anything
        pool = pj_pool_create(pfactory,  // the factory
                              "pool1",   // pool's name
                              4000,      // initial size
                              4000,      // increment size
                              NULL);     // use default callback.
        if (pool == NULL) {
            my_perror("Error creating pool", PJ_ENOMEM);
            return;
        }

        // Demo: allocate some memory chunks
        for (i=0; i<1000; ++i) {
            void *p;

            p = pj_pool_alloc(pool, (pj_rand()+1) % 512);

            // Do something with p
            ...

            // Look! No need to free p!!
        }

        // Done with silly demo, must free pool to release all memory.
        pj_pool_release(pool);
   }

   int main()
   {
        pj_caching_pool cp;
        pj_status_t status;

        // Must init PJLIB before anything else
        status = pj_init();
        if (status != PJ_SUCCESS) {
            my_perror("Error initializing PJLIB", status);
            return 1;
        }

        // Create the pool factory, in this case, a caching pool,
        // using default pool policy.
        pj_caching_pool_init(&cp, NULL, 1024*1024 );

        // Do a demo
        pool_demo_1(&cp.factory);

        // Done with demos, destroy caching pool before exiting app.
        pj_caching_pool_destroy(&cp);

        return 0;
   }
  
BTW:如果要实现嵌入式设备上的SIP电话或者其它,PJSIP是我所见的Coding和Design最为优秀的了,就算不是
为了实现SIP协议栈,它的Coding方式,以及调试的接口,各种基础组件的定义,也让人深刻,可以当作一份
优秀的源代码来阅读,就像小说一般:)

[1] [2]

编辑 webmaster

 
 
 
评论更多>>
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •