协议栈的层次SIP为应用层(Application-Layer)的协议,所以不需要改变操作系统便可以支持。SIP已经获得3GPP(ThirdGenerationPartnershipProject)、3GPP2(ThirdGenerationPartnershipProjectNumber2)等机构认证,成为未来第三代行动通讯(3G)的标准。下面是SIP的分层图示,IETF坚持分层,不同模块功能相对独立,各层之间松散耦合。事务用户层(TransactionUser)事务层(Transaction)传输层(Transport)语法与编码层(SyntaxandEncoding)关于Resiprocate设计首先祭出这面大旗,”类是对概念的描述,面向接口编程;封装变化的概念。”---这不是我讲的,是大师们的口水。Resiprocate中大部分类就是对RFC3261各种SIP元素、组件的封装,并且也体现了RFC协议设计的层次。在面向对象的设计中我们首先就要厘清问题域的所在;SIPStack的设计就是要充分考虑完整展现RFC定义的各种元素和概念以及让这些独立而又关联的元素互动起来成为一个活的系统。可以这样来考虑,比如我们知道RFC定义了一个SIPMESSAGE的概念;下面是从RFC文档拷贝的内容:SIP消息=起始行*消息头部CRLF(空行)[消息体]因此SIPMessage这个概念元素还包括了更多的元素和概念;SIPMessage中我们能抽象出更通用的概念我们暂且叫它Message;起始行的概念E文RequestLine以及StatusLine又包括了很多消息头(这是包容的关系),SIPURL也包括消息头,等等,还有什么参数什么的元素呢;当我们在考虑和提炼这些概念和元素的时候,我们思考怎么抽象他们呢,它们又有什么基本的元素及其共性呢?他们之间的关系如何组织呢?Resiprocate的源码告诉了我们如何去设计和封装这些概念的上佳实现。在Resiprocate中一些RFC3261中定义元素的对应:建议:利用CRC卡片的方式去记录理解Resiprocate中的大量的类及其关系。CRC:类、职责、协作。部分设计的理解OBSERVER/VISITOR/COMMAND/ITERATOR模式,工厂模式(大量容器的使用也是一种变体如:DialogSet),代理类句柄类(界面实现分离,隐藏实现…),……大量的界面类(如AppXXX系列)是遵循大师BS“界面和实现分离”的原则吧;而句柄方式对对象的间接管理是老外的惯用伎俩啦,关于句柄设计从大师BS的著作到EffectiveC++的Handle_Body论和C++沉思录的大段描述再到C++ModelDesign都有发挥和外延,感兴趣可以观之。插播:源码中的大量Clone函数是模仿大师BS的虚拟构造函数一说,是原型模式的体现;源码中对同步的封装值得借鉴,其中有“资源开始即初始化”理论的体现;在DUM部分回调机制所遵循的著名“好莱坞原则”;句柄和代理的一个特点就是重载了operator-、operator*等;源码中也非常注重效率如SipCore部分中大量Hash表的建立。T*operator-(){returnget();}constT*operator-()const{returnget();}T&operator-(){return*get();}constT&operator*()const{return*get();}Handled::Handled(HandleManager&ham):mHam(ham),mId(Handled::npos){mId=mHam.create(this);}Handled::IdHandleManager::create(Handled*handled){mHandleMap[++mLastId]=handled;//typedefHashMapHandled::Id,Handled*HandleMap;//HandleMapmHandleMap;returnmLastId;}1.SIPStack分析1.1ResiprocateSIPStack系统架构图示1.2FIFO流的走向图1.3Sendingdatagram1.4ProcessIncomingUDP2.Application/DUM设计浅析抽象接口:CLASSHANDLED,CLASSInviteSessionHandler(诸如此类)……对象之源:CLASSHANDLED(多态和控制的基础)……交互控制:CLASSHandle,CLASSHandleManager……概念封装成类典型:CLASSDialog,CLASSDialogId,CLASSDialogSet,CLASSDialogSetId,CLASSInviteSession…..Utility工具类:CLASSBaseCreator,CLASSDestroyUsage,CLASSProfile……流动之源:DialogUsageManager::process(),Dialog::dispatch(constSipMessage&msg)……状态机的位置:DialogUsageManager::incomingProcess,DialogSet::dispatch,Dialog::dispatch在整个Resiprocate大家族中事务层概念1的体现是TransactionUser类,而其真正的实现和管理类就是DialogUsageManager;从其:classDialogUsageManager:publicHandleManager,publicTransactionUser能看出来;HandleManager点出了DialogUsageManager的管理功能的本质,并且管理各种对象(Handle是各类对象的句柄)。在整个Resiprocate系统中不管是我们发出或者收到的SIPMessage都是放进了先进先出的队列然后不断轮询处理,这有点象Windows的消息系统,对应收发的消息DUM提供事件通知的机制。DUM利用事件回调模型,事件响应可以选择继承系列XXXHandler抽象接口,并向TU注册,以实现VISITOR模式;我在另外的文档里也提到这是Reactor(Dispatcher,Notifier)模式,应用程序开发者只负责实现具体事件处理程序,并在反应器上注册它们----“好莱坞原则”。1也许是事务用户层DialogUsageManager是sip事务层管理类,是一个大总管的角色;看其Makexxx系列的函数能明白它能发起一系列登陆、会话邀请的动作及其回复。Dum定义了很多句柄管理类,通过它我们能得到真实的对象,从而完成操作,这在事件响应中非常有用。在Dum(DialogUsageManager)的类中基本上这样一条线(以INVITE为例):DialogUsageManager产生DialogSet,DialogSet产生Dialog,Dialog产生InviteSession;InviteSession又分ClientInviteSession和ServerInviteSession。而上面的各个对象的PROCESS或者DISPATCH函数产生的各种状态的变化并触发相应事件。在DUM的IM/PRESENSE部分广泛使用SUBSCRIBE/NOTIFY的模式,目前协议的定义似乎参照成熟的设计模式。个人一直比较喜欢这段论述:session有两种含义,一种是传统意义上的RTP会话,一种是信令意义上的会话。SIP中的会话指后一种,在层次上它在dialog之上,也就是dialog可以看成session的组成单元。二者的分别主要基于目前出现的subscription应用,对于session和subscription可以共享一个dialog,dialog由基本的会话标识组成,如Call-ID,From-Tag,To-Tag,以及一些目的target等共性单元组成。而session除了具备这些单元外,包含INVITE建立起的会话其他内容,例如INVITE引起的状态机处理内容、PRACK处理记录等内容。有一个最为重要的区别是:Session是完成了SDP的Offer-Answer过程,也就是此时双方可以进行双向的RTP传输了。而Dialog只是双方建立了联系,这个联系是通过DialogContext来记录的。在Dialog状态下双方不一定可以作双向的RTP传输。所以必定是Dialog在前,而Session在后,但两者可以同时一起建立。Session是基于SDPMessage的交互,没有SDP的交互,就没有Session。而Dialog是基于请求消息中的HeaderField进行交互。因此两者在层次上也是不一样的。下图是DUM中各种对象实例间的关系表示:DUM中几个重要的类图:3.RESIPROCATESIPCore重要模块的简单介绍SipStack模块SipStack是SipStackCore的面向外界的接口;可以说它是SipStackCore的外覆类(wrapper)或者是界面类(以大师BS的观点来看),它是和外界交互的窗口和协议,具体的实现又分散到更具体的实现类和层次。在整个的协议栈架构中SipStack处于承上启下的位置,它既面向DUM层(表现为向DialogUsageManager服务)又可以直接为外界(如UI)所用;列举其主要面向外界的接口函数:/**AddsaTUtotheTUselectionchain.Tu'sdonotcallreceiveorreceiveAny,theSipStackwillcallpostToTuontheappropriateTu.MessagesnotassociatedwitharegisteredTUgointoSipStack::mTuFifo.*/voidregisterTransactionUser(TransactionUser&);注释基本上已经讲的很清楚,我就补充其交互的细节吧。这个函数基本上能让我们看到TU和SipStack交互间其visitor/observer模式的影子。voidSipStack::registerTransactionUser(TransactionUser&tu){mTuSelector.registerTransactionUser(tu);}回溯SipStack的成员变量:///ResponsibleforroutingmessagestothecorrectTUbasedoninstalledrulesTuSelectormTuSelector;把SipStack中的TransactionUser角色独立出来交与一个独立的类管理是个不错的选择。消息的流向分向两端,一路向下直达Transport层而去,一路向上提交TransactionUser直至UI。因此接口类Message中存在这个函数就不足为奇啦:classMessage{。。。。。。voidsetTransactionUser(TransactionUser*t){tu=t;}TransactionUser*getTransactionUser(){returntu;}TransactionUser*tu;};正是setTransactionUser给予消息TransactionUser归属。而在TransactionState中我们将会看到SipMessage是如何兵分两路的:staticvoidsendToTU(TransactionUser*tu,TransactionController&controller,TransactionMessage*msg);voidsendToWire(TransactionMessage*msg,boolretransmit=false);现在我们先重点关注一下sendToTU:voidTransaction