关于osip协议栈的优化

partysip编译安装和遇到的问题解决 因学习需要,欲安装基于osip库的Partysip proxy。下面是编译安装过程以及中途遇到的问题。 一、准备工作 1.osip库:libosip2-2.2.0.tar.gz 下载地址:http://ftp.gnu.org/gnu/osip/libosip2-2.2.0.tar.gz 2.partysip代码包:partysip-2.2.3.tar.gz 下载地址:http://dow 阅读详情
2008-02-13 15:40:06.0

作者:olivegames

由于工作的原因,需要对osip协议栈进行优化,前段时间在论坛上看到lw3223兄对于osip协议栈hash查找事务的讨论,鉴于此把自己这段时间对osip的优化和心得总结出来大家共享一下。写的比较匆忙,有点乱,大家见谅了。
     众所周知,Osip协议栈是用C语言编写,实现了SIP协议基于事务层的处理,后来作者对协议栈进行了扩展,提供了call级的操作处理,也就是eXosip。Osip小巧,灵活,易扩展,比较方便用来实现UA,但是用作proxy的话性能上有点满足不了需求(听说有个改良版的partysip,没用过,我们这里只讨论osip的优化),有必要对其进行优化一番。
     这里使用的是最新3.0.1的版本,有些固有的影响性能的因素,比如消息的解析,复制,转换到字符串以及释放等暂不予讨论,大家有什么好的方案也可以一起讨论一下。我们可以围绕协议栈线程主执行函数_eXosip_execute()来展开对它的优化工作。
1.1        SIP Message到transaction的映射
     Osip性能低下的一个重要原因便是有太多的for循环,尤其是在事务层SIP消息到事务的匹配,好在osip预留了hash的处理方法,为我们的优化节省了不少的工作量。打开编译宏HAVE_DICT_DICT_H,协议栈便会使用libdict库对四种事务进行hash的插入,查找,删除等。如果您手头有这个库,到这里这一步就可以完成了。由于这个库不是linux自带的,你可能需要自己给协议栈实现一个hash算法,增加osip_hash.c和osip_hash.h两个文件基本上就OK了。
      经过测试,这项操作对性能的提升约1/10左右。由于测试的压力较小,因此查询效率的提升不是很明显,但是当呼叫量和并发数较大时,对性能的改善应该会比较明显。
1.2        Osip状态机的处理效率
     协议栈处理事务事件(这里指osip事件,非eXosip事件)的主函数是osip_xxx_execute(),在这里xxx分别代表osip的四种状态机ict, ist, nict, nist,以下如未经特别说明均使用该准则。
     随便捡一个来看,比如osip_ist_execute()函数,你会发现这个函数也就是轮询事务列表,找到有事件需要处理的事务,然后调用每个状态下对不同事件的状态机处理函数fsm,仅此而已。重点就在轮询,至于它是怎么调用到具体的fsm,稍后再讨论。你可以想象一下,每秒100calls的呼叫率,每个call的接续时间为10秒,那么ist事务列表的长度便是1000。你可以认为循环1000次没什么,但是你要想想主执行函数_eXosip_execute()的调用频率(其实是一直阻塞于该函数中)是非常高的,只要有SIP消息的来往就会产生相应的SIP事件来唤醒协议栈。
     经过实际测试,在nict事务列表平均长度为4xx时,平均不到一个事务需要处理事件,可见四个状态机的执行函数osip_xxx_execute()就不能执行太多的无用操作,所以这里有必要提高轮询事务的效率。
     最简单的方法就是在osip_t结构体里增加四个活动的事务列表osip_xxx_active_transactions,分别对应四个状态机,只存放有事件需要处理的事务,为了不影响到原来的协议栈,也方便以后的调试,所有关于状态机的优化都加上编译宏OSIP_FSM_OPTIMIZE。这样四个状态机的执行函数osip_xxx_execute()就只需要轮询活动事务列表即可。
     需要作出修改的函数如下:
__osip_add_xxx(), 
__osip_remove_xxx_transaction(),                /* 可能不需要修改 */
__osip_transaction_add_event(),
osip_xxx_execute()
     修改时需要注意不要将事务重复添加到活动列表里,以尽量减少活动列表的长度。当osip_xxx_execute()函数从活动列表里取出一个事务后便删除该事务,这样在函数执行完毕后,活动列表就是空的了,保证该列表一直处于低长度下。因此实际上经过测试发现函数__osip_remove_xxx_transaction()里不需要再次试图从活动列表里删除事务了,但为了保险起见,这部分代码我还没有去除。另外,要注意函数__osip_transaction_add_event()的修改,这里可能会遇到信号量的问题。之后对定时器的优化时会提到。
      经过以上的修改,测试协议栈性能有显著的提高,经过统计osip_xxx_execute()这四个函数执行时间减少到了之前的一半。它怎么就才一半呢?继续看这个函数osip_transaction_execute(),它是osip_xxx_execute()最终调用的事务处理函数,原来函数fsm_callmethod()(这个函数定位具体的fsm并调用)是用已知的状态和事件类型查找列表的方式来调用实际的fsm的,还不赶快改成数组的,别节约内存了。这里需要改动xxx_fsm.c中的的__xxx_load_fsm()和__xxx_unload_fsm()函数以及fsm_callmethod()函数。改动比较繁琐,注意不要改错了哦:)
     最后再次测试,四个状态机执行函数osip_xxx_execute()的执行事件已经减少到原来的1/4了。以上的改动之后,对于事务的处理基本上克服了事务数增多导致的性能非线性下降的因素。
1.3        超时事件的产生
     Osip的定时器超时事件是通过轮询所有事务的每个定时器而产生,然后将其放入事务列表(注意,这里可能需要将事务放入活动列表,因为之前事务处理完成后是从活动列表里删除了的),而每次SIP消息的事件唤醒协议栈后都会触发定时器遍历操作的执行,可见定时器的效率非常低下,并且大部分的定时器通常都不会超时。
     改进的方法就是给osip增加一个定时器模块,这里大家可以参考相对定时器的实现。主要的思想就是将所有定时器进行排序,最先超时的放在前面,这样在触发定时器事件的时候通常只需要判断一下最前面的那个定时器。这对于osip定时器效率的提升大有帮助,虽然在启动定时器的时候要考虑排序的问题,至少在我的测试中这里的消耗还不至于影响到总体性能。当然,精益求精的你可能会考虑双向有序链表的插入问题了,如果有好的解决方法可别忘了通知我啊,呵呵。当然,为了尽量减少这类消耗,我的实现是按RFC3261规定的osip四种状态机下的定时器种类分类,所有同类的定时器都放到同一个定时器组(这个要取决于你实现的定时器了),启动定时器的时候是从链表的后面开始,通常在定时器长度相同的情况下,新加入的定时器总是最后超时,那么它就应该放到链表的最后位置。这样,一定程度的减少了启动定时器时的消耗,当然有几个重发请求的定时器的超时事件是变的,不过这已经没多大影响了,毕竟重发请求又不是经常要发生的。
     对定时器的优化改动可能会比较多。你需要参考RFC3261,在相应的状态下启动或者停止对应的定时器。为了不对源代码作过多的修改,你需要添加两类回调函数,一是进入某个状态时,二是退出某个状态的时候,然后将定时器的起停操作放到这些回调函数里去,最后由函数__osip_transaction_set_state()来调用。
     具体的改动涉及到xxx.c和xxx_fsm.c,我将状态切换回调函数(起停定时器)放到了xxx_fsm.c里,定时器超时回调函数(产生定时器事件)放到了xxx.c里。最后,用定时器组的触发函数(取决于你设计的定时器)替换掉四个定时器执行函数
osip_timers_xxx_ execute()。
     经过测试,以上改动性能提升非常显著,之前未经优化,osip_timers_xxx_ execute()执行事件是优化过的osip_xxx_execute()的1.5倍,优化后变为了1/10。
     需要大家注意的是,在之后的压力测试中发现了之前提到过的信号量的问题。之前在将事务加入到活动列表时(__osip_transaction_add_event())之前加了互斥,但是发现协议栈一运行就阻塞,然后就取消了互斥,但是呢,压力测试一段时间后协议栈就crash了,呵呵:)最后总算发现了调用该函数的某些时候加了互斥(比如定时器超时事件),某些时候又没有加互斥,头疼~~~没办法,只好做了该函数的两个版本!
     经过上面的优化后,在相同的测试压力下,协议栈整体性能提升了一倍,并且消除了大部分的导致性能非线性下降的因素。
1.4        Call资源的释放
      经过对协议栈的深入分析和测试,发现释放call资源(遍历所有的call)的函数(主要时eXosip_release_terminated_calls)调用过于频繁,也是每个事件都会触发一次。考虑到资源的释放不用那么及时,通常是在某个定时器超时后才需要释放,于是考虑让资源成批释放,启动一秒级的周期定时器来执行call资源的释放,具体多少秒执行一次,大家可以调整定时器的长度,我设的是5秒。
      由于最终释放事务(eXosip.j_transactions)的资源时,该列表可能会比较长,因此将列表的遍历改为迭代器遍历,因为通过协议栈的osip_list_get()函数遍历链表的效率较低。
这项优化工作量算是很小的了,但是对性能的提升却非常实惠,经测试整体性能继续提高了一倍。至此,协议栈的性能比未经优化时已提升了4倍。
      当然,这里也可以模仿定时器的优化一样只对超时了的事务进行资源释放,但我考虑这样修改好像比较麻烦,最终放弃了。有高手可以在这个函数上继续做文章,对协议栈的优化应该很有帮助。
5        Transaction的移除
     事务的移除(只是从osip协议栈中移除,但仍被TU(eXosip)使用)对事务列表进行了遍历。由于osip的列表不能直接删除中间某个节点,原有的list iterator又不方便读取(主要不方便取得list的最后一个元素的迭代器,需要遍历list),因此实现一新的双向list替换协议栈原有list,并增加接口osip_list_get_last()直接获得链表尾的迭代器。
在事务的结构体里增加一迭代器成员,用于储存该事务在事务列表中的位置信息以便移除事务时可以直接通过迭代器来移除而不用遍历整个事务列表。
     这里需要注意,为了保险起见,在hash里删除事务失败(找不到)后,我仍然轮询了事务列表,后来测试时发现函数__osip_remove_xxx_transaction()可能会被重复调用导致第二次调用时hash删除失败对事务列表进行了遍历!

其他的优化:
6        消息到字符串的转换
     这部分代码存在比较多的内存拷贝和sprintf函数的调用,由于这个函数调用频繁,所以有必要对其进行优化。由于sprintf函数性能低下,因此将其通通更改为memcpy,但是这样做需要对sprintf函数输出的内容进行拆分重组。另外去除内存copy时,需要对大部分的消息内的结构体转字符串的函数重写一个版本。因此这项操作耗费了比较多的时间,也可能出错,需要经过比较详细的测试。
     修改后,这部分代码的性能提升了将近一半,同sendto函数耗费时间差不多,加上消息日志的打印,发送消息的函数性能提升空间已经不大了。这项优化感觉性价比比较低,不感兴趣的同学可以不用去管它
1.7        字符串复制的优化
     这个函数osip_strdup()同样简单,但是使用频率应该是系统里最高的了。去除一些不必要的操作,改strncpy为memcpy。

总结
      经过以上改进,协议栈的整体性能提升至原来的5倍。经过测试,随着在线数的增加UA的性能会有所下降,主要原因是因为eXosip还没有优化,UA访问eXosip提供的        API时带来了一定程度的性能下降。现在性能瓶颈主要在集中于SIP消息的解析,到字符串转化,复制,释放等,相关函数如下:
osip_message_parse();        /* 还没做优化 */
osip_message_to_str();        /* 已优化 */
osip_message_clone();
osip_message_free();        
     如果对消息内的内存分配机制进行改进的话,最后两个函数有较大的提升空间,但是改动涉及面会很广。
经过测试,当在线数增加到256后,eXosip带来的性能下降所占的比重已经比较大了,导致最后UA占的CPU已经超过了协议栈的1/2,而在线数不多的时候不到1/3,加上测试程序的影响,非协议栈程序所耗CPU已经接近协议栈了。可以看出对eXosip进行优化后,性能应该还有一定的提升空间。
      最后,希望有高手能做到更进一步的消息层面的优化,基本上也就是上面几个函数了,有机会大家可以互相认识探讨一下。

原文地址:http://tongxinbing.blog.china.com/200802/1911930.html

SIP应答消息状态码 SIP应答消息状态码与功能类型 状态码 状态说明临时应答(1XX) 100 Trying 正在处理中180 Ringing 振铃181 call being forwarder 呼叫正在前向182 queue 排队181* session progress 会话进行会话成功(2XX) 200 OK 会话成功重定向(3XX) 300 multiple 多重选择301 move... 阅读详情

相关推荐

基于oSIP开源库的SIP代理服务器PartySIP[一]

Partysip 是基于osip实现的的sip服务器。实现了注册服务、重定向、定位、事务状态/无状态机。和eXosip框架思路一样,只是模块实现上面由于功能有所不同而区别。

嵌入式与人工智能天地 8083

FFmpeg4.3系列之28:SIP+eXosip+pjsip小白入门

敬告:该系列的课程在抓紧录制更新中,敬请大家关注。敬告: 该系列的课程涉及:FFmpeg,WebRTC,SRS,Nginx,Darwin,Live555,等。包括:音视频、流媒体、直播、Android、视频监控28181、等。我将带领大家一起来学习:学习sip协议的基本原理、流程、结构;编译开源库源码osip,eXosip,pjsip(包括windows和Linux两套环境);使用eXosip或pjsip进行案例实战;具体内容包括:  1.sip协议讲解,包括原理、结构、协议内容、流程分析等。2.osip与eXosip的源码编译,使用eXosip进行案例实战并详解流程。3.pjsip的源码编译,使用pjsip进行案例实战并详解流程。

OSIP协议栈在物联网设备中的实战:如何用C语言实现轻量级SIP终端

本文深入探讨了如何在资源受限的物联网设备中,使用C语言和OSIP协议栈实现轻量级SIP终端。文章通过对比主流SIP协议栈,详细阐述了OSIP在嵌入式环境下的选型优势、内存优化策略、在VxWorks等实时操作系统上的移植要点,并结合实战案例提供了从架构设计到核心信令流程的完整实现方案,助力开发者应对物联网音视频通信的挑战。

weixin_29284657的博客 219

深入浅出:OSIP协议栈在嵌入式系统中的应用与优化技巧

本文深入解析OSIP协议栈在嵌入式系统中的高效应用与优化技巧,重点介绍其轻量级SIP实现、内存管理优化及实时性保障策略。通过具体代码示例和性能数据,展示如何降低内存消耗40%、处理时延<5ms,并支持2000+并发对话,为VoIP终端等嵌入式通信设备提供可靠解决方案。

weixin_29216957的博客 175

OSIP协议栈实战:如何用C语言实现一个简单的SIP客户端(含完整代码示例)

本文详细介绍了如何使用C语言和OSIP协议栈实现一个简单的SIP客户端,包含完整的代码示例和开发环境配置指南。通过模块化架构和高效内存管理,OSIP协议栈为开发者提供了轻量级、易扩展的SIP实现方案,适用于VoIP终端、嵌入式设备等多种实时通信场景。

q3r4s5t的博客 191

从零开始:手把手教你用OSIP 2.3.1.0搭建自己的SIP服务器(附常见问题排查)

本文详细介绍了如何使用OSIP 2.3.1.0协议栈从零开始搭建SIP服务器,包括环境准备、安装步骤、核心代码实现及常见问题排查。通过实战示例和优化建议,帮助开发者快速掌握SIP协议栈的应用,适用于VoIP和多媒体通信场景。

ww90123的博客 526

osip状态机分析

osip状态机分析 关于osip协议栈的优化

weixin_34309435的博客 177

从零开始:用OSIP 2.3.1.0搭建你的第一个SIP服务器(附完整代码示例)

本文提供了一份基于OSIP 2.3.1.0协议栈从零搭建SIP服务器的实战指南。内容涵盖环境配置、核心模块初始化、消息接收与事务分发机制,并详细解析了如何处理INVITE请求及SDP协商,附有完整代码示例,帮助开发者快速掌握SIP服务器开发的核心流程与OSIP库的应用。

quiet的专栏 503

HYSipServer - 支持GB/T 28181标准的企业级SIP信令服务器

HYSipServer是基于osip2协议栈开发的SIP信令核心服务,完全支持国标GB/T28181协议。系统包含SIP协议栈实现、设备管理、媒体协商等核心模块,采用多线程架构设计,具备高性能事务处理和实时监控能力。通过对象池和线程池优化实现企业级稳定性,支持设备注册、视频点播、PTZ控制等完整监控功能,并提供SDK开发包和信令监控工具。系统采用模块化设计,包含SIP服务核心、RTP传输、安全通信等组件,满足大规模视频监控平台的信令处理需求。

wu_jin_hua的专栏 316

osip2与exosip2协议栈源码深度解析与实战

尽管 WebRTC、gRPC、MQTT 等新技术层出不穷,但 SIP 仍在 VoIP、视频会议、安防监控等领域牢牢占据主导地位。而之所以历经二十年仍被广泛采用,正是因为它们体现了极简、可移植、可定制的工程哲学。它不像某些框架那样“什么都帮你做好”,而是给你一套乐高积木,让你自由搭建想要的形态。无论是做一个极简软电话,还是构建百万级SIP代理服务器,你都能从中找到灵感。

weixin_42163404的博客 897

osip2 exosip2开源SIP协议栈源码深度解析

为了满足特定业务需求(如计费标识、QoS标记),常需引入私有头域(Private Header),通常以前缀X-开头。

weixin_30838971的博客 568

正在写看开源的sip协议栈osip代码的心得

前段时间猛看osip的代码, 现在在写点东西, 给后来者抛砖引玉

阿闷的专栏 1608

深入解析partysip源码:osip基础SIP通信实现

会话初始协议(SIP)是一个应用层控制(信令)协议,用于创建、修改和终止多媒体会话,例如电话呼叫、视频会议、多媒体分发和在线游戏。SIP是一个基于文本的协议,类似于HTTP,可以用于实现各种通信功能,如呼叫转移、会议呼叫和消息发送等。它允许端点发现对方,并协商一个或多个媒体流的参数。SIP的设计灵感来自于互联网的Web模型,它支持独立于底层传输的网络应用。通过支持SIP的应用服务器,可以实现许多传统电话网络中无法提供的服务。

weixin_28487725的博客 1195

SIP协议栈源代码:构建高效通信应用的基石

SIP协议栈源代码:构建高效通信应用的基石 去发现同类优质开源项目:https://gitcode.com/ 项目核心功能/场景 SIP协议栈源代码,构建互操作注册服务器、用户代理和中间服务器。 项目介绍 在现代通信领域,SIP(Session Initiation Protocol)协议是一个至关重要的技术,它负责初始化、管理和终止各种网络会话。SIP协议栈源代码,即OSIP,是一个开源的C语言...

gitblog_06780的博客 758

深入解析set_clock_groups:异步时钟约束的最佳实践与陷阱规避

本文深入解析了FPGA/芯片设计中set_clock_groups命令在异步时钟约束中的核心作用与最佳实践。文章对比了同步时钟、异步时钟与不重叠时钟的区别,强调了正确使用set_clock_groups避免时序分析陷阱的重要性,并提供了与set_false_path的优先级差异分析及实战规避方法,帮助设计者确保时序收敛与电路可靠性。

weixin_29232121的博客 373

BQ27220燃料计量芯片与Arduino库kode_bq27220实战指南

燃料计量(Fuel Gauge)是嵌入式电池管理系统的核心技术,通过电压、电流、温度多维建模实现荷电状态(SOC)与健康状态(SOH)的动态估算。其原理基于电化学阻抗补偿算法(如CEDV),区别于简单电压查表法,具备自学习与老化适应能力。该技术显著提升便携设备续航预测精度与低功耗可靠性,广泛应用于TWS耳机、可穿戴设备及医疗电子等场景。本文围绕TI BQ27220高精度燃料计量IC及其配套Arduino库kode_bq27220展开,覆盖硬件连接规范、I²C初始化要点、SOC/SOH实时读取、EDV阈值配置

weixin_35671843的博客 331

几种开源SIP协议栈对比

随着VoIP和NGN技术的发展,H.323时代即将过渡到SIP时代,在H.323的开源协议栈中,Openh323占统治地位,它把一个复杂而又先进的H.323协议栈展现在普通程序员的眼前,为H.323普及立下了汗马功劳。而然当在SIP时代,则出现了群雄割据的状况,SIP相对于H.323简单,灵活,于是各种协议栈层出不穷,下面将详细对比最具有代表性的5个开源项目:OPAL, VOCAL, sipX,

1502

UVM(5)-TLM通信

TLM是一种基于事务 (transaction) 的通信方式,通常在高抽象级语言例如SystemC或者SV/UVM中作为模块之间的通讯方式。

2301_76431006的博客 2106

开源SIP协议栈综合评估与技术选型推荐报告

开源SIP协议栈技术选型分析 本文对四大主流开源SIP协议栈(PJSIP、reSIProcate、Sofia-SIP和libeXosip2)进行深度技术评估,重点聚焦PJSIP架构。PJSIP采用分层设计(PJLIB基础层、PJNATH穿透层、PJMEDIA媒体层、PJSIP-SIP协议层及高层API PJSUA2),提供从底层控制到快速开发的完整解决方案。其核心优势包括:全面的SIP协议支持、先进的NAT穿透能力(STUN/TURN/ICE)、强大的音频会议桥设计、端到端安全机制(TLS/SRTP)以及卓

greenspan的专栏 1414

Winform美化框架AntdUI中Table的使用方法

使用核心注意点: 数据模型中属性名需要完全与new Column里的列名一致否则添加数据源则无法读取到详细内容。

wevix的博客 3676

STM32F103C8T6 + GY-906红外测温:手把手教你用CubeMX和HAL库搞定IIC驱动(附完整工程)

本文详细介绍了如何使用STM32F103C8T6和GY-906红外测温传感器(基于MLX90614芯片)实现非接触式温度测量。从STM32CubeMX工程创建、HAL库驱动适配到温度数据采集与处理,提供完整的开发流程和常见问题解决方案,帮助开发者快速掌握红外测温技术。

weixin_29188043的博客 254
上一篇: SIP入门(二):建立SIP服务器
下一篇: Joomla插件—Top of the Page回到顶部按钮-中文版发布
cheneymei
博客等级 码龄16年 144粉丝 9原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值