一、通用设计

1.1   架构

1.1.1        通信图

下面的图展示了SIP消息在PJSIP组件间从后端到前端如何传递的。

1.1.2        类图

下面的图显示类视图

1.2   Endpoint

SIP 协议栈的核心是SIP endpoint,它由透明的pjsip_endpoint的表示,endpoint具有下面的属性和职责

l  内存储工厂,为所有的SIP组件分配内存

l  具备定时器堆实列,为所有的SIP组件调度定时器

l  传输管理起实例,传输管理器负责传输SIP消息并且控制消息的解析和打印。

l  拥有单实例PJLIB io 队列,IO队列采用proactor模式分发事件。

l  提供了线程安全的轮询功能,应用程序的线程能够查询定时器和socket事件(PJSIP自身不常见任何线程)

l  管理PJSIP模块,PJSIP模块主要以为着扩展SIP stack,而不仅仅限于消息的解析和打印。

l  从传输模块接收SIP消息,并且分发到各个模块中。

1.2.1        内存池分配和释放

为了保证线程的安全性以及在整个应用中策略强一致性,所有的SIP内存都需要在endpoint中完成分配。比如:内存池缓存,未使用的内存被保留在以后使用而不是销毁。

Endpoint提供下面的函数分配和释放内存池

pjsip_endpt_create_pool()

pjsip_endpt_release_pool()

当endpoint被pjsip_endpt_create()创建时,应用一定要指明由endpoint使用的内存池工厂。在整个生命周期内Endpoint持有内存池工厂的指针,将来备用创建和释放内存。

1.2.2        定时器管理

Endpoint 拥有一个独立定时器堆实例,所有SIP组件的定时器创建和调度都需要通过endpoint 完成。Endpoint提供下面的函数管理定时器

pjsip_endpt_schedule_timer()

pjsip_endpt_cancel_timer()

endpoint的poll函数被调用时,检查定时器是否过期。

1.2.3         轮询栈

Endpoint 提供独立的函数(pjsip_endpt_handle_events())为了检查定时器和网络事件的出现,应用可以指定准备等待多久去检查事件的出现。

Pjsip 栈从不创建线程,整个栈的运行过程都依赖于应用所创建的线程,不管是API被调用或者是轮询函数被调用。

轮询功能优化等待时间依赖于定时器堆的内容,比如:当它找到定时器将在下个5S过期,他等待socket事件的时间,将不会比5S长,在无网络事件出现时,应用程序等待超过5S是没有必要的,当然每个平台的定时器的精度是不一样的。

1.3   线程安全和线程的兼容性

1.3.1        线程安全

线程安全的讨论是比较麻烦的事情,但是,幸运的是,下面的设计原则,在整个协议中的应用都保持了一致性。

对象一定是线程安全的,但是数据结构一定不是线程安全的。

看到这个主题,很自然的想到,对象和简单数据结构的区别不是那么清晰,但是有一些例子可以提供,可能更明白写。

数据结构的例子:

PJLIB的数据结构,比如:

l  链表、数组、哈希表、字符串、内存池。

l  SIP消息的元素,URLs、header fields和SIP消息

这些数据结构并不是线程安全的,数据结构的线程安全由包含他们的对象保证。如果数据结构是线程安全的,将会严重的影响协议栈的性能并且消耗操作系统的资源。

相比之下,PJSIP的对象一定是线程安全的,比如:

l  PJLIB 对象,比如ioqueue

l  PJSIP 对象,比如: endpoint、transactions、dialogs等。

 

1.3.2        复杂性

更糟糕的是,一些对象在头文件中暴露了他们的声明(pjsip_transaction 和 pjsip_dialog)。

虽然API暴露可以保证线程的安全性,应用在访问数据结构前,必须通过pj_mutex_lock获取到对象的互斥锁。

更糟糕的是,dialog暴露的不同的API锁定dialog,应用程序应该调用pjsip_dlg_inc_lock和pjsip_dlg_dec_lock() 替代pj­_mutex_lock和pj_mutex_unlock。两种处理方式区别是:

Dialog的inc/dec保证了dialog将不会被销毁在函数调用时。而pj_mutex_unlock会因为dialog销毁了而导致层序crash。

考虑下面的例子:

pj_mutext_lock(dlg->mutex)

pjsip_dlg_end_session(dlg,…)

pj_mutex_unlock(dlg->mutex)

在上面的例子中,应用可能会crash,因为pjsip_dlg_end_session可能会销毁dialog在某些情况下。例如:INVITE事务没有被应答,事务会被马上销毁,导致dialog被立刻销毁。Dialog

Inc/dec可以通过增加dialog的引用计数,防止这类情况的发生。再end_session时,dialog 不会被销毁,dialog 可能会在dec_lock函数中被销毁。所以正确的调用顺序应该如下:

Pjsip_dlg_inc_lock(dlg)

Pjsip_dlg_end_session(dlg)

Pjsip_dlg_dec_lock

最最糟糕的是,锁的调用顺序一定是正确的,否则引起死锁。比如:应用想去锁dialog和dialog 的 transaction,应用必须获得dialog mutex在获取transaction mutex之前,否则当其他的线程以相反的顺序拿锁时,将会引起死锁。

1.3.3         解决办法

幸运的是,应用程序很少会直接获取对象的锁,所以上面的问题很少会发生。应用应该使用对象的API访问对象,API会对象检查,保证了lock的正确性,避免了死锁和crash的产生。

应用程序的回调被对象调用,这些回调被调用时,对象的锁已经获取到了。所以应用能够安全的获取对象的数据结构,不必要获取对象的锁。

PJSIP开发指南的更多相关文章

  1. PJSIP开发指南-第二章

    一.模块 2.1    模块框架 模块框架的主要作用是在应用程序组件之间分发SIP消息,PJSIP的所有的组件,包括dialog和transaction都是以模块方式实现的,没有模块,核心协议栈将不知 ...

  2. ASP.NET Aries 开源开发框架:开发指南(一)

    前言: 上周开源了Aries开发框架后,好多朋友都Download了源码,在运行过程里,有一些共性的问题会问到. 所以本篇打算写一下简单的开发指南,照顾一下不是太看的懂源码的同学,同时也会讲解一下框架 ...

  3. FreeMarker模板开发指南知识点梳理

    freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题) freemarker是什么? FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生 ...

  4. Jetty使用教程(四:21-22)—Jetty开发指南

    二十一.嵌入式开发 21.1 Jetty嵌入式开发HelloWorld 本章节将提供一些教程,通过Jetty API快速开发嵌入式代码 21.1.1 下载Jetty的jar包 Jetty目前已经把所有 ...

  5. JVM 平台上的各种语言的开发指南

    JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...

  6. iOS原生地图开发指南续——大头针与自定义标注

    iOS原生地图开发指南续——大头针与自定义标注 出自:http://www.sxt.cn/info-6042-u-7372.html 在上一篇博客中http://my.oschina.net/u/23 ...

  7. Angularjs中文版本开发指南发布

    从本人开始在写关于Angularjs的文章开始,也算是见证了Angularjs在国内慢慢的火起来,如今的Angularjs正式如日中天.想知道为什么Angularjs会这么火,请移步angularjs ...

  8. nodejs开发指南读后感

    nodejs开发指南读后感 阅读目录 使用nodejs创建http服务器; supervisor的使用及nodejs常见的调式代码命令了解; 了解Node核心模块; ejs模板引擎 Express 理 ...

  9. Libgdx 开发指南——目录

    本系列文档选译自libgdx github项目 wiki : https://github.com/libgdx/libgdx/wiki 由于关于Libgdx的中文文档非常稀缺,因此在这里对官方Wik ...

随机推荐

  1. Elasticsearch入门指南

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 这篇文章主要是记录一下最近在学的 ...

  2. 【NOIP2015】斗地主 题解(DFS+贪心)

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的AAA到KKK加上大小王的共545454张牌来进行的扑克牌游戏.在斗地主中,牌的大小关 系根据牌的数码表示如下: ...

  3. Python高手是怎样炼成的!

    很多想从事python行业的朋友都会问到,零基础如何自学成为Python高手?根据小北多年教育的经验,我总结了几个小建议,想看干货的请看下文! 如何克服入门难问题? 其实小北觉得,最好的方法就是和一群 ...

  4. 干!一张图整理了 Python 所有内置异常

    在编写程序时,可能会经常报出一些异常,很大一方面原因是自己的疏忽大意导致程序给出错误信息,另一方面是因为有些异常是程序运行时不可避免的,比如在爬虫时可能有几个网页的结构不一致,这时两种结构的网页用同一 ...

  5. [机器学习] keras:MNIST手写数字体识别(DeepLearning 的 HelloWord程序)

    深度学习界的Hello Word程序:MNIST手写数字体识别 learn from(仍然是李宏毅老师<机器学习>课程):http://speech.ee.ntu.edu.tw/~tlka ...

  6. ZoneJS 的原理与应用

    目录 序言 Zone 是什么 ZoneJS 的原理 ZoneJS 的应用场景 参考 1. 序言 ZoneJS 是 Angular 团队受到 Dart 的 Zone 的启发,为 Angular v2 及 ...

  7. Git常用命令参考手册

    配置 # 查看全局配置列表 git config -l # 查看局部配置列表 git config --local --list # 查看已设置的全局用户名/邮箱 git config --globa ...

  8. 第四周:卷积神经网络 part 3

    第四周:卷积神经网络 part 3 视频学习 语义分割中的自注意力机制和低秩重建 语义分割(Semantic Segmentation) 概念:语义分割是在像素级别上的分类,属于同一类的像素都要被归为 ...

  9. 记一次mysql数据库被勒索(上)

    家里搞了台旧电脑做NAS,安装了nextcloud,选择了mysql做为数据库. 当时也没有想太多,mysql数据库密码随便设置了个123456,用的一切正常. 然后,听说可以找电信申请换个公网IP的 ...

  10. asp.net core mvc和angular项目的一些问题

    最近公司布置任务,用asp.net core mvc和angular改写原来的一个用Silverlight做的项目.从来没搞过,找了两本书看了一天,又看了一天代码,大致心里有底了,就开始动手.没想到一 ...