yate学习笔记Word格式.docx
- 文档编号:18095080
- 上传时间:2022-12-13
- 格式:DOCX
- 页数:24
- 大小:79.47KB
yate学习笔记Word格式.docx
《yate学习笔记Word格式.docx》由会员分享,可在线阅读,更多相关《yate学习笔记Word格式.docx(24页珍藏版)》请在冰豆网上搜索。
)
该引擎已
YateC++
类为基础,将把所有模块组件连接在一起,上图描述了各组件之间的交互过程。
(2)
模块(
Modules
大部分功能由运行时加载的模块来实现。
这些模块以动态链接库为载体,作为插件被引擎或外部程序的特定模块加载。
被外部程序特定模块加载时,需能够与引擎或其他模块之间相互交互(通信)。
(3)
消息(
Messages
模块(包括插件和外部模块)之间的交互是依靠消息实现的。
消息提供了一种可扩展,可定制,并且与具体技术无关的交互机制。
每个模块在需要得到信息或者需要通知其他模块时只需要创建并向引擎提交消息,引擎负责会将消息传递给合适的目标。
以
ClassEngine
为核心,构建了插件式的管理体系,按照观察者(发布
-
订阅)的设计模式来处理数据流。
类根据配置文件加载插件,缺省参数的情况下,会加载指定目录下所有的插件。
然后运行插件的初始化函数
initialize()
完成插件的初始化。
ClassYate
提供了一些
API
(静态函数)用于加载分析配置参数,加载特定模块,和指定目录下的所有模块。
//
加载指定目录下模块
参数
relPath
相对主模块的路径
boolloadPluginDir(constString&
relPath);
注册插件,只有注册过的插件才能被初始化
boolRegister(constPlugin*plugin,boolreg=true);
加载指定模块
boolloadPlugin(constchar*file,boollocal,boolnounload);
private
voidloadPlugins();
从插件目录中加载插件
voidinitPlugins();
初始化插件
基于列表的发布
订阅示例由客户端、服务和数据源程序组成。
可以有多个客户端和多个数据源程序同时运行。
客户端订阅服务、接收通知,然后取消订阅。
数据源程序向服务发送将与所有当前订户共享的信息。
ClassEngine:
:
m_dispatcher:
m_handles
维护着订阅者列表,每个订阅者都实现了以下接口用于接收通知。
classMessageHandler
virtualboolreceived(Message&
msg)=0;
}
还提供了一些列的
(静态成员函数)
安装注册订阅者的接口,参数指定订阅的事件类型
staticboolinstall(MessageHandler*handler);
staticbooluninstall(MessageHandler*handler);
发送事件通知,所有注册了该事件类型的都有机会得到事件内容
//enqueue
为非阻塞函数,即将事件通知加入消息列表中,不关系事件处理的结果
//dispatch
为阻塞函数,即必须等到订阅者处理完事件才能返回。
staticboolenqueue(Message*msg);
staticbooldispatch(Message*msg);
一般调用
enqueue
把
message
放进了一个消息队列里,再由一个
Dispatcher
类来对消息顺序处理,相当于向所有订阅者发布消息。
插件必须从
Module
类派生,并实现
这个虚函数,另外,根据需要实现
Message
的处理类MessageHandler
。
在
里,按照主题安装
MessageHandler
,如下所示:
Engine:
install(newAuthHandler(s_cfg.getIntValue("
general"
"
auth_priority"
70)));
上例的
AuthHandler
即是从
中派生而来,它必须实现
received()
虚函数,以处理接收到的message
如果处理成功,则
应该返回
true
,否则返回
false
如果某类
DrModule
需要处理多个事件,首先订阅者必须从
MessageReceiver
派生,
就是从MessageReceiver
派生的,可以处理多了事件。
另外消息处理类必须由
MessageRelay
派生,当然MessageRelay
,也是从
的。
同样在
Dr-Module:
initialize
中,安装如下
TokenDictDrModule:
s_messages[]={
{"
engine.halt"
DrModule:
Halt},
call.progress"
Progress},
call.route"
Route},
chan.text"
Text},
msg.route"
ImRoute},
{0,0}
installRelay(Halt);
installRelay(Progress);
installRelay(Route,200);
installRelay(Text);
installRelay(ImRoute);
installRelay(ImExecute);
YATE
的架构是典型的发布
订阅机制,很好的实现了平台的可扩充性,减少了模块与平台、模块与模块之间的耦合,可以说架构是非常清晰的。
比如用户认证的功能,
里有三个模块提供三种方式对用户进行认证:
文件方式(
Regfile
),
Radius
方式,数据库方式。
这三种方式都是接收并处理
"
user.auth"
、"
user.register"
等消息,其先后顺序根据
install
时定的优先级排序。
处理的结果由
的
retValue()
带回。
这种处理机制虽然优点很突出,但性能上的缺点也很明显,因为在对消息队列的处理是单线程而且要对所有订阅者进行遍历,效率比较低。
2Yate
中的消息
中,消息取代函数成为模块间主要的交互方式。
这样的好处在于,当一个模块改变时,其他独立的模块不用做任何修改。
另外,因为我们能够轻松的跟踪到消息的传递过程,所以调试起来相对容易。
消息包括以下几个组成部分:
名字(
name
)
——
消息类型的标识,允许消息处理器通过名字进行匹配
(2)
返回值(
returnvalue
一个用字符串表示的处理消息之后的返回值
(3)
时间(
time
消息被创建的时间;
这对于排队的消息检查等待时长非常重要
(4)
参数(
parameters
可能有多个或
0
个参数组成,每个参数由名称、值对构成。
每个处理器都能根据参数进行不同的动作,或者修改参数本身。
未定义参数必须忽略。
所有的消息在
内部是二进制形式的。
然而我们可以通过
rmanager
模块提供一个对人可读的形式。
YATE
内部消息传递通过内存共享(
memorysharing
)的方式,提高系统的性能。
其他传递方式如管道或Sockets
,没有内存共享灵活和高效。
当被传递到外部模块(
externalmodules
)时,消息可被转换成字符串编码的形式,这样所有能处理文本的外部模块都可以处理消息了。
可参考文档
externalmodule
,获取更多详细信息。
消息被消息处理器(
)处理。
消息处理器接收名字匹配的消息,可以对其中的组成部分进行修改,然后停止处理此消息(释放),或让此消息滑动到下一个操作者。
消息处理器接收消息分发器通知的顺序在其向引擎注册时提供的优先级决定。
优先级数字越小,优先级越高。
对于相同优先级的消息处理器,调用顺序是不确定的。
调用顺序按以下的规则:
*
同名的消息调用顺序是不会改变的
为了避免不确定性,如果消息处理器被移除,并插入一个同等优先级的消息处理器,则他们的顺序由她的的内存地址决定。
2.1
消息系统工作示例
以下是
“call.rotue”
在消息系统重的工作过程例子
当某个电话打来时,消息是这样产生的:
1.Message*m=newMessage("
);
2.
m->
addParam("
driver"
iax"
3.
if(e->
ies.calling_name)
4.
callername"
e->
ies.calling_name);
5.
else
6.
session->
callerid);
7.
ies.called_number)
8.
called"
ies.called_number);
9.
10.
dnid);
然后我们将消息发送给引擎,检查是否有模块(
module
)接收并处理了,最后必须将消息销毁。
1.
if
(Engine:
dispatch(m))
Output("
Routing
returned:
%s"
m->
retValue().c_str());
Nobody
routed
the
call!
destruct();
上面的处理方式是阻塞式的,模块发送消息之后需要等待该消息被发送之后才进行后续的处理。
中还有一种“发射后忘记”(
fire-and-forget
)的消息机制,非阻塞式消息机制,这种消息被存储在引擎中的一个队列中,当消息被分发后,由引擎负责释放。
这种消息一般都是事关系统全局的重要消息,例如错误报警,如下代码所示:
*m
=
new
Message("
alert"
reason"
Hardware
malfunction"
enqueue(m);
如果我们编写的模块需要处理一个路由请求(极有可能是其他模块产生的),我们首先需要声明一个名为RouteHandler
的类,并从MessageHandler
基类继承。
class
RouteHandler
public
{
RouteHandler(int
prio)
MessageHandler("
prio)
}
virtual
bool
received(Message
&
msg);
然后,由于在
received
方法中实现,他是类
中是纯虚函数,我们必须重载。
RouteHandler:
msg)
const
char
*driver
msg.getValue("
Debug(DebugInfo,"
Route
for
driver
driver);
don'
t
actually
route
anything,
let
continue
return
false;
最后,在插件的
initialized
方法中,安装此消息处理器
void
RegfilePlugin:
m_route
RouteHandler(priority);
install(m_route);
这样,该插件就能处理“
call.route
”消息了,这个例子中实际上只是接收了消息但没有做任何动作,如果需要什么操作,在
方法里实现即可。
中的几乎所有消息操作者都是按照这样的框架实现的。
2.2
消息流示例
以呼叫进入为例:
路由
当一个通道模块检测到有呼叫进入
,它便发送
call.route
(2)
消息来决定将此呼叫路由到哪个位置。
Call.route
消息将被叫号码映射到一个呼叫目标。
连接
当呼叫对象已知以后,呼入通道将其呼叫端点(
CallEndPoint
)附在
call.execute
消息上
(4)
接收方应该将它的呼叫端点连接到
中携带的呼叫端点上。
在等待对端接受呼叫期间应该发送
call.ringing
消息(6)
,当呼叫被接受时,
call.ansered
被发送。
会话期间
在会话期间,
chan.dtmf
消息
(8,9)
能在两个方向上发送。
挂机
当呼入通道检测到挂机
(10)
,它将断开其呼叫端点。
断开呼叫端点将引发两个通道
chan.disconnected
消息和
chan.hangup
消息的(图中未包括)发送。
从消息流的示例我们可以看到,
对呼叫的抽象很清晰,在逻辑上符合人们的思维习惯,比较容易理解。
2.3
消息类型
引擎消息(
Enginemessages
engine.start
由引擎发送给普通模块,通知他们
准备就绪,并已进入主循环
engine.halt
engine.init
engine.busy
engine.help
mand
engine.status
engine.timer
通道消息(
Channelmessages
chan.attach
chan.connected
chan.disconnected
双音多频信号(
Dual-tonemulti-frequencysignaling
chan.hangup
chan.masquerade
chan.notify
chan.record
chan.rtp
chan.startup
chan.text
chan.connect
chan.locate
chan.control
chan.replaced
呼叫消息(
Callmessages
call.answered
call.cdr
call.drop
call.execute
call.progress
call.ringing
call.route
call.preroute
call.update
call.conference
用户消息(
Usermessages
user.account
user.auth
user.login
user.notify
user.register
user.unregister
资源描述
/
通知消息
(Resourcesubscribe/notifymessages)
resource.subscribe
resource.notify
6.SIP
(SIPmessages)
sip.<
methodname>
xsip.generate
编解码特定协议消息
(Encodeordecodeprotocolspecificmessages)
isup.decode
isup.encode?
isup.mangle
网络操作消息(
Socketoperationmessages
socket.stun
socket.ssl
socket.peel?
集群相关消息(
Clusteringrelatedmessages
cluster.locate
即时信息相关消息(
Instantmessagingrelatedmessages
msg.route?
msg.execute?
11.Jabber/XMPPmessages
xmpp.generate?
xmpp.iq
12.
其他消息(
Miscellaneousmessages
database
monitor.query
monitor.notify
3.Yate
模块创建方法
在实际应用中,可能需要编写自己的模块插入到系统中或者替换掉自己的模块,例如,使用商用的SIP
协议栈替代Yate
中开源的SIP
协议栈,所以,编写在Yate
框架下编写自己的模块是使用Yate
平台必备的技能。
Yate可分为两个部分
*Yate内核
*Yate模块
*Yate内核提供基础,辅助API以及消息系统
*Yate模块使用Yate内核实现特定的功能
Yate模块的类型
Yate模块可分为一下几种
1.通道
2.路由器
3.电话历史记录(CallDetailRecorder)
4.计费程序
5.其他模块
如何指定模块的类型
模块类型在这里涉及许多概念性的东西。
Yate的设计中并不区分模块的种类,而是根据模块处理的消息类型来区分模块类型。
例如一个通道模块接受call.exec
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- yate 学习 笔记