libjingle源码解析(2)--libjingle是怎么运作的?

7 篇文章 1 订阅
4 篇文章 0 订阅

本文主要总结至libjingle源码和官方文章:http://code.google.com/apis/talk/libjingle/libjingle_applications.html

ligjingle的总体架构如下图:



1.Application模块

Ligjingle的应用程序首先调用XMPP Messaging Component的XmppClient对象进行登录,然后做一些message,iq,presence等request/respond操作。

其次,每个application可能包含一个或多个session client用来做P2P操作,比如远程协助,视频会议,音频连接,文件共享等等。


2.XMPP Messaging Component.模块

此模块主要由三个部分组成:XmppClient,LoginHandler和Xmpp Helper Task.此模块主要做相当于一个peer的防火墙的功能,连接服务器和客户端,负责发送所有本地的stanza请求(即XMPP协议内容),并负责接收服务器的stanza请求,并分发到各个Helper Task里。

  • XmppClient主要是代理登录,发送stanza,接收stanza。之所以说是代理,是因为真正发送,接收的消息都是通过XmppEngine来实现的。
  • XmppEngine能注册多个XmppStanzaHandler回调,然后所有从服务器接收的Stanza都转发到已绑定的XmppStanzaHandler进行过滤,而实际上是回调XmppTask对象。
  • XmppStanzaHandler类定义如下:

//! Callback to deliver stanzas to an Xmpp application module.
//! Register via XmppEngine.SetDefaultSessionHandler or via
//! XmppEngine.AddSessionHAndler.  
class XmppStanzaHandler {
public:
  virtual ~XmppStanzaHandler() {}
  //! Process the given stanza.
  //! The handler must return true if it has handled the stanza.
  //! A false return value causes the stanza to be passed on to
  //! the next registered handler.
  virtual bool HandleStanza(const XmlElement * stanza) = 0;
};

  • XmppTask是所有XmppHelperTask的基类,并继承自XmppStanzaHandler,主要有监听,过滤XmppEngine对象转发过来的Stanza消息。XmppTask有多种类型,当取类型为HL_PEEK时,只有监听功能,无法做到过滤;而其他类型可以做到过滤。过滤是有HandlerStanza函数来完成,当返回为true时,过滤,否则XmppEngine枚举下一个绑定的XmppTask继续尝试分发、过滤。
  • 所有XmppHelperTask都要继承XmppTask并要重载HandlerStanza函数和ProcessStart函数。
    • HandlerStanza是用来过滤,相当于windows消息处理的GetMessage()
    • 而ProcessStart是用来处理HandlerStanza过滤的消息。
    • 比如在源代码example/call/presencepushtask.h里:

class PresencePushTask : public XmppTask {
 public:
  PresencePushTask(XmppTaskParentInterface* parent, CallClient* client)
    : XmppTask(parent, XmppEngine::HL_TYPE),
      client_(client) {}
  virtual int ProcessStart();

  sigslot::signal1<const Status&> SignalStatusUpdate;
  sigslot::signal1<const Jid&> SignalMucJoined;
  sigslot::signal2<const Jid&, int> SignalMucLeft;
  sigslot::signal2<const Jid&, const MucStatus&> SignalMucStatusUpdate;

 protected:
  virtual bool HandleStanza(const XmlElement * stanza);
  void HandlePresence(const Jid& from, const XmlElement * stanza);
  void HandleMucPresence(buzz::Muc* muc,
                         const Jid& from, const XmlElement * stanza);
  static void FillStatus(const Jid& from, const XmlElement * stanza,
                         Status* status);
  static void FillMucStatus(const Jid& from, const XmlElement * stanza,
                            MucStatus* status);

 private:
  CallClient* client_;
};

    • 这里PresencePushTask类,通过HandleStanza过滤所有presence相关的stanza并在ProcessStart里处理所有来自服务器的用户状态更新消息。
  • LoginHandler部分是由XmppPump来负责的。主要调用XmppClient的connect和disconnect方法建立、断开连接,监听SignalStateChange事件来获取连接信息,类型为STATE_OPENED的事件表示连接成功。

3.Session Logic and management commponent模块。

所有p2p session逻辑相关的部分都放在了这个模块。可以session可能是处理文件传输的连接,或者可能是视频会话,或者音频会话等等。

  • 我们需要继承SessionClient来处理每个Session相关具体任务,比如文件传输Session:当接收对端客户端建立一个文件传输session的时候,如果此Session是新创建的,SessionManager对象会回调所有注册的SessionClient的OnSessionCreate的接口,并以SessionManger创建的Session对象为参数穿进去;如果是已有的Session则会调用Session的OnIncomingMessage方法。
  • Session对象则抽象了两个peer之间的数据传输接口。当收到OnSessionCreate回调时,SessionClient可以通过Session的方法Accept来接受创建,Reject来拒绝。
  • 那怎么读写p2p数据呢?
    • 首先需要调用session的CreateChannel方法获取TransportChannel对象指针,然后监听TransportChannel的事件SignalReadPacket来接收数据,通过SendPacket方法来发送数据。

class TransportChannel: public sigslot::has_slots<> {
 public:
//......

  // Attempts to send the given packet.  The return value is < 0 on failure.
  virtual int SendPacket(const char *data, size_t len) = 0;
  // Signalled each time a packet is received on this channel.
  sigslot::signal3<TransportChannel*, const char*, size_t> SignalReadPacket;
//......
};

4.Peer to peer Component模块。

此模块才是libjingle核心,libjingle项目的初衷也是能够把模块设计得完美,使得所有需要通过P2P传输数据的应用层调用libjingle时,不用担心数据传输的稳定性,可靠性,高效性。

  • 刚才上面提到,当服务器发送stanza时XmppEngine把Stanza发送到XmppTask过滤,在这个模块,SessionManagerTask代理SessionManager过滤session相关的stanza,并转发到SessionManager对象,如下:

class SessionManagerTask : public buzz::XmppTask {
 public:
  ......

  virtual int ProcessStart() {
    const buzz::XmlElement *stanza = NextStanza();
    if (stanza == NULL)
      return STATE_BLOCKED;
    session_manager_->OnIncomingMessage(stanza);
    return STATE_START;
  }

 protected:
  virtual bool HandleStanza(const buzz::XmlElement *stanza) {
    if (!session_manager_->IsSessionMessage(stanza))
      return false;
    QueueStanza(stanza);
    return true;
  }


}  // namespace cricket

  • SessionManager类在这里起到连接上述3个模块的桥梁作用。
  • 当上层调用SessionManager创建的Session对象的CreateChannel时,实际上是调用P2PTransport的CreateChannel方法。
  • 上层通过P2PTransport创建P2pTransportChannel的类的。
  • P2pTransportChannel继承自TransportChannel,并创建多个不同的Connection,每个Connection代表一个TCP或者UDP或者SSL连接。上层传输数据最终是调到P2pTransportChannel的相关方法,当发送,接收数据时,P2pTransportChannel选择表现最好的Connection进行传输。

5.其他

LigJingle提供了很多接口供我们继承,用于特定的个性化Session,同时也提供了不少实例(如pcp,login,call)让调用者更容易的理解框架思路。当需要着手研究libjingle时,如果能够充分的利用已成的实例,对于缩短熟悉时间,很有帮助。






  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值