• GLOOX 1.0 API ---框架


    改定履历:

    2011-08-19-------------------新建文本文档

    2011-08-25--------------------增加XMPP官网链接

    2011-09-02-------------------新增对GLOOX1.0API文档Main Page页翻译

            

            个人研究XMPP已经有大约一个星期的时间了,基本过程是先看了三天的RFC,包括RFC3290,RFC3291两个主要协议,然后就是研究GLOOX1.0了。XMPP除了这两个核心协议之外还有很多的XEP扩展协议。另外比较成熟的XMPP协议栈是GLOOX1.0版。前文已经贴出了RFC文档,从这篇文章开始详细介绍GLOOX,由于本人也是边学边记录,有高手飘过时请不吝赐教。

            先贴出一下XMPP一些相关资源:

    XMPP官网

    gloox官方网站---这里可以了解gloox的官方信息,开发文档等

    gloox1.0API文档---个人将官方的API文档整站下载下来打包,方便本地查看,强烈建议大家详细看一下文档的Main Page页,以对整个gloox的设计有一个大的层面上的理解

    RFC3920------XMPP核心协议

    RFC3921------即时消息和出席信息

    xmpp协议PPT----XMPP PPT文档

            先这些吧,以后随时补充

    ---------------------------------------------------------------------------------------------------------------------

    GLOOX协议栈是基于所谓“观察者”设计模式设计的,如果你熟悉“观察者”设计模式或者不熟悉但是在去深入了解GLOOX之前能去看一下“观察者”模式会对学习GLOOX很有好处。其主要思想就是将观察者“注册”到“被观察者”那里,“被观察者”有什么风吹草动,观察者都会知道,而进一步的处理就是在你的程序里实现“观察者”的若干虚函数。

    环境搭建的话,本人用的是vs2008,下载下来gloox1.0,新建一个工程把gloox下src目录里所有的.h和.cpp全部加载,再添加一个工程用于对gloox进行测试,将两个工程的生成目录及依赖设置好即可。

    ----------------------------------------------------------------------------------------------------------------------

    补充:博主近日学习GLOOX,重读了API Main Page页,觉得Main Page页对于新手从较高层面上把握GLOOX有很大帮助,且这里往往是新手容易忽略的最直接的一手资料信息来源,于是决定花时间翻译出来。限于本人英文水平,大家可参照原英文文档查看:


    Introduction

    GLOOX的设计遵循了所谓的观察者设计模式,含义是一切都是基于事件驱动的。使用GLOOX不如Jabber/XMPP网络有两种方式------做为客户端或组件。C++ XMPP服务器库请参考<http://camaya.net/glooxd>.

    Note:

    XMPP详细规格说明书(RFC 3290)的11.5小节要求,线路上交换的数据只能是UTF-8编码方式,由于GLOOX不知道输入的数据是哪种编码,所以GLOOX要求输入数据必须是有效的UTF-8编码。

    Event Handlers:

    GLOOX里最重要的工具就是事件处理器(event hanbdlers),当前,除了有为RFC中定义的基本协议服务的4种事件处理器,还有为XEP实现里的事件和附加功能服务的其它许多事件处理器。另外,一个日志处理器、一个一般标签处理器和一个连接事件处理器都是有效的。

    通常这些处理器都是虚接口,你可以继承它们派生出一个类,并且实现一些这些虚函数。然后你可以注册这样的一个子类对象到各自的协议实现里。下面是一个简单的例子:

    1. class MyClass : public PresenceHandler 
    2.    public
    3.      // reimplemented from PresenceHandler 
    4.      virtual void handlePresence(const Presence& presence ); 
    5.  
    6.    [...] 
    7. }; 
    8.  
    9. void MyClass::handlePresence( const Presence& presence ) 
    10.    // extract further information from the Presence object 
    1. class MyClass : public PresenceHandler  
    2.  {  
    3.    public:  
    4.      // reimplemented from PresenceHandler  
    5.      virtual void handlePresence( const Presence& presence );  
    6.   
    7.    [...]  
    8.  };  
    9.   
    10.  void MyClass::handlePresence( const Presence& presence )  
    11.  {  
    12.    // extract further information from the Presence object  
    13.  }  

    在某个地方你可以像下面这样做:
    1. OtherClass::doSomething() 
    2.   Client* client = new Client( ... ); 
    3.   [...] 
    4.   MyClass* handler = new MyClass( ... ); 
    5.   client->registerPresenceHandler( handler ); 
    1. OtherClass::doSomething()  
    2. {  
    3.   Client* client = new Client( ... );  
    4.   [...]  
    5.   MyClass* handler = new MyClass( ... );  
    6.   client->registerPresenceHandler( handler );  
    7. }  
    然后你可以使用Stanza类提供的众多getters(即get前缀的成员函数)进一步提取节中的数据
    现在,每次接收到一个presence节(非subscription节)时,handlePresence都会被调用,参数是当前节。然后你可以使用Stanza类提供的众多getters(一般来讲是get前缀的方法,此处理解为获取stanza各数据的方法)进一步提取节中的数据以进一步处理。

    几乎所以的事件处理器的工作方式都是与这个例子相似的,接下来以使用连接事件处理器(class ConnectionListener)为例,再举一例:

    1. class MyClass : public ConnectionListener 
    2.    public
    3.      virtual void onConnect(); 
    4.  
    5.      virtual bool onTLSConnect( ... ); 
    6. }; 
    7.  
    8. void MyClass::onConnect() 
    9.    // do something when the connection is established 
    10.  
    11. bool MyClass::onTLSConnect( const CertInfo& info ) 
    12.    // decide whether you trust the certificate, examine the CertInfo structure 
    13.    return true// if you trust it, otherwise return false 
    1. class MyClass : public ConnectionListener  
    2.  {  
    3.    public:  
    4.      virtual void onConnect();  
    5.   
    6.      virtual bool onTLSConnect( ... );  
    7.  };  
    8.   
    9.  void MyClass::onConnect()  
    10.  {  
    11.    // do something when the connection is established  
    12.  }  
    13.   
    14.  bool MyClass::onTLSConnect( const CertInfo& info )  
    15.  {  
    16.    // decide whether you trust the certificate, examine the CertInfo structure  
    17.    return true// if you trust it, otherwise return false  
    18.  }  

    Note:

    ConnectionListener是一个比较奇特的接口。你必须重新实现ConnectionListener::onTLSConnect()这个接口,如果你想成功连接一个启用了TLS/SSL服务器的话。尽管GLOOX试图检查服务器的证书,但不会自动的信任该服务器。必须由客户端程序员或用户来决定是否信任此服务器。是否信任就由onTLSConnect()的返回值来表示,FLASE意味着你不信任该服务器,结果就是与服务器的连接中断。

    先去吃饭了,回来待续……

    Components

    Jabber/XMPP网络中的一个组件是加载到服务器上的,它运行在实际的服务软件之外,但它有相似的权限,组件使用XEP-0114中描述的协议去连接和验证一个服务器.类Component 支持该协议并且可以用于创建一个新的Jabber component.简单的例子如下:

    1. Component* comp = new Component( ... ); 
    2. comp->connect(); 
    1. Component* comp = new Component( ... );  
    2. comp->connect();  

    Clients

    一个客户端可以是终端用户的聊天客户端,一个机器人或者是一个没有和特殊服务器绑定在一起的简单实体。类Client实现了连接一个XMPP 服务器所需要的功能。一个例子如下:

    1. class MyClass : public ConnectionListener, PresenceHandler 
    2. public
    3.      void doSomething(); 
    4.  
    5.      virtual void handlePresence( ... ); 
    6.  
    7.      virtual void onConnect(); 
    8.  
    9.      virtual bool onTLSConnect( const CertInfo& info ); 
    10. }; 
    11.  
    12. void MyClass::doSomething() 
    13.    JID jid( "jid@server/resource" ); 
    14.    Client* client = new Client( jid, "password" ); 
    15.    client->registerConnectionListener( this ); 
    16.    client->registerPresenceHandler( this ); 
    17.    client->connect(); 
    18.  
    19. void MyClass::onConnect() 
    20.    // connection established, auth done (see API docs for exceptions) 
    21.  
    22. bool MyClass::onTLSConnect( const CertInfo& info ) 
    23.    // examine certificate info 
    24.  
    25. void MyClass::handlePresence( Presence* presence ) 
    26.    // presence info 
    1. class MyClass : public ConnectionListener, PresenceHandler  
    2. {  
    3. public:  
    4.      void doSomething();  
    5.   
    6.      virtual void handlePresence( ... );  
    7.   
    8.      virtual void onConnect();  
    9.   
    10.      virtual bool onTLSConnect( const CertInfo& info );  
    11. };  
    12.   
    13. void MyClass::doSomething()  
    14. {  
    15.    JID jid( "jid@server/resource" );  
    16.    Client* client = new Client( jid, "password" );  
    17.    client->registerConnectionListener( this );  
    18.    client->registerPresenceHandler( this );  
    19.    client->connect();  
    20. }  
    21.   
    22. void MyClass::onConnect()  
    23. {  
    24.    // connection established, auth done (see API docs for exceptions)  
    25. }  
    26.   
    27. bool MyClass::onTLSConnect( const CertInfo& info )  
    28. {  
    29.    // examine certificate info  
    30. }  
    31.   
    32. void MyClass::handlePresence( Presence* presence )  
    33. {  
    34.    // presence info  
    35. }  
    Note

    GLOOX官方并不支持5223上的连接方式。例如:在XML串先于SSL加密之前被发送,因为这是历史遗留的方法况且不符合标准的XMPP协议。然而,GLOOX提供了一个ConnectionTlS类,做为附加功能,允许你去绑定一个这样的连接。

    默认情况下,Client::connect()是阻塞的,直到连接终止(Client::disconnect()被调用,或者服务器终止连接)。


    阻塞和非阻塞连接

    对于某些种类的机器人来说阻塞式的连接(缺省的行为)是非常理想的方式。几乎所有的机器人都是对来自于服务器的事件做出响应。然而,对某些终端用户或带有GUI应用的客户端来说就不那么完美了。

    这些情况下就需要用到非阻塞式的连接了。如果调用ClinetBase::connect(false),函数将会在绑定连接后立即返回。接下来程序员就有责任初始化一些从SOCKET接收到的数据。

    一种最简单的方法是以一个超时值(微秒)做为参数周期性的调用ClientBase::recv(),缺省值-1意味着调用是阻塞的,直到有数据到达,对数据的解析也是自动的。

    作为周期性地轮询一种替换办法,你可以获取连接的原始文件描述符。你可以在该文件描述符上使用select()并且当select上的数据有效时使用ClientBase::recv()。你可能直接从文件描述符得不到任何数据,也没有办法为解析器提供数据。

    为了得到文件描述符,你必须手动设置一个连接类(ConnectionTCPClient),就像这样:

    1. Client* client = new Client( ... ); 
    2. ConnectionTCPClient* conn = new ConnectionTCPClient( client, client->logInstance(), server, port ); 
    3. client->setConnectionImpl( conn ); 
    4.  
    5. client->connect( false ); 
    6. int sock = conn->socket(); 
    7.  
    8. [...] 
    1. Client* client = new Client( ... );  
    2. ConnectionTCPClient* conn = new ConnectionTCPClient( client, client->logInstance(), server, port );  
    3. client->setConnectionImpl( conn );  
    4.   
    5. client->connect( false );  
    6. int sock = conn->socket();  
    7.   
    8. [...]  

    有可能像下面这样获取文件描述符:
    1. Client* client = new Client( ... ); 
    2. client->connect( false ); 
    3. int sock = static_cast<ConnectionTCPClient*>( client->connectionImpl() )->socket(); 
    4.  
    5. [...] 
    1. Client* client = new Client( ... );  
    2. client->connect( false );  
    3. int sock = static_cast<ConnectionTCPClient*>( client->connectionImpl() )->socket();  
    4.   
    5. [...]  
    显然,只要你没有使用setConnectionImpl()设置一个不同的连接类型就会工作。

    Note

    在0.9以后的版本里这已经发生了改变,ClientBase::fileDescriptor()不在可用了。

    Roster Management

    RFC3921定义了如何管理一个人的联系列表(花名册)。在GLOOX中,类RosterManager实现了这个功能。一组简单函数有效地实现了订阅和取消订阅实体的出席。也可以在没有实际订阅此联系人出席的情况,把他加入到自己的花名册中。另外,接口RosterListener对应于各种花名册相关的事件提供了一组回调函数。

    如果你依上所述创建了一个客户端对象,那么你可以获取一个RosterManager对象。Client::rosterManager()返回一个该类对象的指针。

    Privacy Lists

    同样地,“隐私列表”也定义在RFC3921中,一个隐秘列表可以明确地禁止或允许 从联系人接收或发给联系人数据节,区分不同的联系人。你可以自己定义基于JID,节类型等的规则。类PrivacyManager 和类PrivacyListHandler虚接口在隐私列表的处理上比较灵活。

    1. PrivacyManager* p = new PrivacyManager( ... ); 
    2. [...] 
    3. PrivacyListHandler::PrivacyList list; 
    4. PrivacyItem item( PrivacyItem::TypeJid, PrivacyItem::ActionDeny, 
    5.                   PrivacyItem::PacketMessage, "me@there.com" ); 
    6. list.push_back( item ); 
    7.  
    8. PrivacyItem item2( PrivacyItem::TypeJid, PrivacyItem::ActionAllow, 
    9.                    PrivacyItem::PacketIq, "me@example.org" ); 
    10. list.push_back( item2 ); 
    11.  
    12. p->store( "myList", list ); 
    1. PrivacyManager* p = new PrivacyManager( ... );  
    2. [...]  
    3. PrivacyListHandler::PrivacyList list;  
    4. PrivacyItem item( PrivacyItem::TypeJid, PrivacyItem::ActionDeny,  
    5.                   PrivacyItem::PacketMessage, "me@there.com" );  
    6. list.push_back( item );  
    7.   
    8. PrivacyItem item2( PrivacyItem::TypeJid, PrivacyItem::ActionAllow,  
    9.                    PrivacyItem::PacketIq, "me@example.org" );  
    10. list.push_back( item2 );  
    11.   
    12. p->store( "myList", list );  
    Authentication

    GLOOX支持XEP-0078定义的旧样式的基于IQ节的鉴权机制,也支持若干SASL机制。可以参考Client类文档说明以获取更多信息。

    Sending and Receiving of Chat Messages

    对于消息传输推荐使用MessageSession接口。它处理消息的发送和接收,也处理包括消息事件和聊天状态(例如“打字中……”)等。查看MessageSession类文档以获取更多细节。

    Protocol Extensions (XEPs)

    XMPP标准基金会发布了许多核心协议的扩展,称为XMPP Extension Protocols(XEPs)(XMPP扩展协议)。一些扩展协议已经在GLOOX中得到实现:

    XEP-0004 Data Forms 
    XEP-0012 Last Activity 
    XEP-0013 Flexible Offline Message Retrieval 
    XEP-0022 Message Events (see MessageSession for examples) 
    XEP-0027 Current Jabber OpenPGP Usage (see GPGSigned and GPGEncrypted ) 
    XEP-0030 Service Discovery 
    XEP-0045 Multi-User Chat 
    XEP-0047 Used with File Transfer 
    XEP-0048 Bookmark Storage 
    XEP-0049 Private XML Storage 
    XEP-0050 Ad-hoc Commands 
    XEP-0054 vcard-temp 
    XEP-0060 Publish-Subscribe 
    XEP-0065 SOCKS5 Bytestreams , used with File Transfer and HTTP and SOCKS5 Proxy support
    XEP-0066 Out of Band Data , also used with File Transfer 
    XEP-0077 In-Band Registration 
    XEP-0078 Non-SASL Authentication (automatically used if the server does not support SASL)
    XEP-0079 Advanced Message Processing 
    XEP-0083 Nested Roster Groups (automatically used if supported by the server. see RosterManager )
    XEP-0085 Chat State Notifications (see MessageSession for examples) 
    XEP-0091 Delayed Delivery (old spec) 
    XEP-0092 Software Version (integrated into Service Discovery ) 
    XEP-0095 Stream Initiation , used with File Transfer 
    XEP-0096 File Transfer 
    XEP-0106 JID Escaping 
    XEP-0114 Jabber Component Protocol 
    XEP-0115 Entity Capabilities (used automatically internally) 
    XEP-0124 Bidirectional-streams Over Synchronous HTTP (BOSH) 
    XEP-0131 Stanza Headers and Internet Metadata 
    XEP-0138 Stream Compression (used automatically if gloox is compiled with zlib and if the server supports it)
    XEP-0145 Annotations 
    XEP-0153 vCard-based Avatars 
    XEP-0172 User Nickname 
    XEP-0184 Message Receipts 
    XEP-0199 XMPP Ping 
    XEP-0203 Delayed Delivery (new spec) 
    XEP-0206 see BOSH 
    XEP-0224 Attention 
    XEP-0256 Last Activity in Presence

    更进一步的扩展可以用类StanzaExtensions很容易的实现。

    File Transfer

    对于文件传输,GLOOX实现了XEP-0095(流初始化协议)和XEP-0096(文件传输)协议的信号机制;为传输实现了XEP-0065(SOCKS5 Bytestreams 流字节)和XEP-0047(带内字节流)。参考 SIProfileFT类

    HTTP and SOCKS5 Proxy support

    gloox 有能力穿过http及SOCKS5代理,即便是连锁代理。参考ConnectionHTTPProxy类 和 ConnectionSocks5Proxy类.

  • 相关阅读:
    Repeater 双向排序
    将具有固定格式的text 类型中的数据分离出来的一种方法
    ASP.NET 快速构建应用程序页面主框架
    2分分页处理存储过程通用存储过程
    C#3.0之匿名类型
    常用的js收集
    用CSS实现DataGird滚动而表头不动
    Lucene.Net 创建索引和检索
    Lucene.net 实现全文搜索
    SQL 中操作日期的几个函数
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318345.html
Copyright © 2020-2023  润新知