From: http://yate.null.ro/pmwiki/index.php?n=Main.Messages
消息是YATE的一个主要组成部分。所有的模块间通信都使用消息而不使用函数调用,这主要是因为我们考虑当一个模块发生变化的时候不影响或不依赖于其他模块,也因为我们知道模块直接传递的参数,使得我们的调试模块可以更容易些。 一个消息由以下几个部分组成: * 名字(name)——消息类型的标识,允许消息处理器通过名字进行匹配 * 返回值(return value)—— 一个用字符串表示的处理消息之后的返回值 * 时间(time)—— 消息被创建的时间;这对于排队的消息检查等待时长非常重要 * 参数(parameters)—— 可能有多个或0个参数组成,每个参数由名称、值对构成。每个处理器都能根据参数进行不同的动作,或者修改参数本身。不知道的参数必须忽略。 所有的消息在YATE内部是二进制形式的。然而我们可以通过rmanager模块提供一个对人可读的形式。 YATE内部消息传递通过内存共享(memory sharing)。在这种方式下,可以提高系统的性能。其他可以考虑的形式如管道或Sockets,没有内存共享灵活和高效。 当被传递到外部模块(external modules)时,消息被转换成字符串编码的形式,这样所有能处理文本的外部模块都可以处理消息了。 可参考文档external module, 获取更多详细信息。 消息由消息处理器处理,每个消息处理器仅处理与它名字相同的消息。他们可以任意修改消息元素(参数,返回值,甚至消息名称),一个消息处理器处理完之后,可 由下一个消息处理器处理。 消息处理器处理消息的顺序,再插入派发器中就已经决定。处理顺序按照消息处理器的优先级决定,优先级值越低的预处理器优先级越高,先与优先级值高的接受到消息。 对于相同优先级的消息处理器,调用顺序是不确定的。调用顺序按以下的规则: *同名的消息调用顺序是不会改变的 *为了避免不确定性,如果消息处理器被移除,并插入一个同等优先级的消息处理器,则他们的顺序由她的的内存地址决定。 以下是“call.rotue”在消息系统重的工作过程例子 当某个电话打来时,消息是这样产生的:
Message *m = new Message("call.route"); m->addParam("driver","iax"); if (e->ies.calling_name) m->addParam("callername",e->ies.calling_name); else m->addParam("callername",e->session->callerid); if (e->ies.called_number) m->addParam("called",e->ies.called_number); else m->addParam("called",e->session->dnid);
然后我们将消息发送给引擎,检查是否有模块(module)接收并处理了,最后必须将消息销毁。
if (Engine::dispatch(m)) Output("Routing returned: %s",m->retValue().c_str()); else Output("Nobody routed the call!"); m->destruct();
引擎在得到上述消息,将其发送到所有注册名为“route”消息处理器模块中。 对于fire-and-forget类型消息,他们先存储在引起的消息队列中并由引擎内部的线程池进行延后派发。一旦消息派发完成后则由引擎将其销毁。
Message *m = new Message("alert"); m->addParam("reason","Hardware malfunction"); Engine::enqueue(m);
为了处理route消息请求(很有可能在另外一个模块中),,我们首先声明一个从MessageHandler派生的类RouteHandler。
class RouteHandler : public MessageHandler { public: RouteHandler(int prio) : MessageHandler("call.route",prio) { } virtual bool received(Message &msg); };
然后,由于方法received在类MessageHandler中是纯虚函数,我们必须重载。
bool RouteHandler::received(Message &msg) { const char *driver = msg.getValue("driver") Debug(DebugInfo,"Route for driver %s",driver); // don't actually route anything, let message continue return false; }
最后,在插件的initialized方法中,安装此消息处理器
void RegfilePlugin::initialize() { m_route = new RouteHandler(priority); Engine::install(m_route); }