登陸 - 驗證密碼上線 - 斷開 - 好友狀態(tài) - 接收消息和發(fā)送消息 - 獲取好友信息(列表&名片)和添加刪除好友 - 聊天室 - 消息回執(zhí) - 添加AutoPing 為了監(jiān)聽服務器是否有效,增加心跳監(jiān)聽。
1. 為什么選擇XMPP協(xié)議
2. XMPP的基本網(wǎng)絡結(jié)構(gòu) - 2.1 XMPP客戶端 - 2.2 XMPP服務器 - 2.3 XMPP網(wǎng)關
3. 服務器端介紹 - 3.1 什么是Openfire - 3.2 為什么使用Openfire
4. XMPP協(xié)議的組成 RFC 3920 XMPP
5. XMPP地址格式
6. XMPP消息格式 - 6.1 message type屬性 + to屬性 + from屬性 - 6.2 presence - 6.3 iq (Info / Query)
通訊方式選擇 - P2P + 服務器中轉(zhuǎn)
網(wǎng)絡連接方式 - 基于TCP的長連接 + 基于HTTP短連接PULL的方式
協(xié)議選擇 - XMPP?+?SIP?+?MQTT?+?私有協(xié)議
私有協(xié)議的設計 - 序列化選擇 + 協(xié)議格式設計
其他問題 - 協(xié)議加密 + 快速連接(登錄) + 連接保持 + 消息可達 + 文件上傳優(yōu)化
Overview of the XMPP Framework
Up to date instructions on how to install XMPP Framework manually?
Introduction
框架分為2個部分:
1. XMPP Core
2. The extensions (roster, XEP's, optional supporting utilities, etc)
拓展包含如名單支持,自動重連和多樣的XMPP拓展實現(xiàn)。
XMPP Core {#core}
XMPP框架的核心文件在 "Core" 文件夾中,文件如下:
XMPPStream
XMPPParser
XMPPJID
XMPPElement
XMPPIQ
XMPPMessage
XMPPPresence
XMPPModule
XMPPLogging
XMPPInternal
框架的核心是 XMPPStream 類,這是你主要用到的類,同時這個類是所有拓展和自定義代碼要接入的地方。它有許多有趣的特性,被用于使框架靈活,可拓展,易于從上層開發(fā)。我們將在本文檔的后面深入的討論這些。
XMPPParser 是?XMPPStream 的內(nèi)部類。你可以大膽的猜想它是干嘛的。在任何情況下,你都不需要與 parser 打交道。
XMPPJID 提供了一個不可變的 JID (Jabber Identifier)實現(xiàn)。它支持 JID's 解析,同時抽取了JID在多種形式下的不同部分。它遵循 NSCopying 協(xié)議,以便 JID's 可能用作?NSDictionary?中的keys。也遵循 NSCoding 協(xié)議。
XMPPElement 是3個主要的 XMPP 元素的基礎類: XMPPIQ & XMPPMessage & XMPPPresence。其拓展了 NSXMLElement,因此你擁有整 NSXML foundation 用于觀察任何 XML元素。更多細節(jié)在 section Elements: IQ, Message, & Presence.
XMPPModule 為可選可拓展提供了基礎類。如果自己寫app,就會想創(chuàng)建自己的類,注冊獲得自己的delegate調(diào)用。
XMPPLogging 提供快速,強大,靈活的日志框架。XMPP Logging
XMPPInternal 關聯(lián) core 和多種高級底層的拓展
Elements: IQ, Message, & Presence
XMPPElement 擴展 NSXMLElement,因此你擁有整 NSXML foundation 用于觀察任何 XML元素。
XMPPIQ -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
XMPPMessage -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
XMPPPresence -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
除了 NSXML foundation,框架提供?NSXMLElement+XMPP?分類,有多樣的便利方法來確保編碼更加精確可讀。如:
[element? attributeIntValueForName:@"age"];
更多信息,戳?Working With Elements
XMPPStream Configuration {#configuration}
XMPPStream 實例的配置分為幾步:
Configuring how to connect to the xmpp server
Adding delegates
Adding modules
Connecting
Authenticating
Configuring the connection
對大多數(shù)人,只需簡單一步,設置 stream 的 myJID 屬性。如:
xmppStream.myJID = [XMPP ? JIDjidWithString:@"user@gmail.com"];
The xmpp stream will figure out the rest by following the XMPP RFC. This involves doing an SRV 搜索 for _xmpp-client._tcp.domain。上面的列子,用 gmail, google 服務器將很可能返回像 "talk.google.com",之后 xmppStream 將連接服務器。如果 SRV 搜索失敗,之后 xmppStream 將簡單的連接 JID's 域名。
如果你知道連接的 xmpp 服務器沒有 xmpp SRV 記錄,你能告訴 xmppStream 跳過 SRV 搜索,通過指定 hostName。如
xmppStream.myJID = [XMPP ?JIDjidWithString:@"user@myCompany.com"];
xmppStream.hostName = @"myCompany.com";
當你用一個開發(fā) xmpp 服務器,hostname 也很容易得到。但是服務器僅能在本地網(wǎng)絡獲得,或者沒有 DNS 地址。如:
xmppStream.myJID = [XMPP ?JIDjidWithString:@"user@dev1.myCompany.com"];
xmppStream.hostName =@"192.168.2.27";
另一個可選屬性是 hostPort。默認,根據(jù) xmpp 說明,幾乎所有服務器運行 port 5222。但是,如果你的服務器運行不同的 port,你也能設置 hostPort 屬性。
Adding Delegates
XMPPStream 有許多有趣的特性,被用于使框架靈活,可拓展,易于從上層開發(fā)。其中之一就是運用?MulticastDelegate。
What is a MulticastDelegate?
xmpp 框架需要支持一個非限制數(shù)量的拓展。這包含官方拓展,也包含其他拓展或者自定義代碼。因此傳統(tǒng)的代理模式不行了。XMPP 模塊和拓展需要被分離為他們自己獨立的類,然而,所有這些類需要獲得 delegate 方法。同時,標準的 NSNotification 架構(gòu)也不起作用了,因為一些代理要求一個返回值。(而且,從 notification 的 userInfo 字典中提取參數(shù)真TM煩人)
因此一個多播代理允許你用標準模式接入框架,但是它允許多類獲得相同的 delegate 通知。好處在于你可以把所有 xmpp 處理代碼放進一個類中。也能分離處理代碼到多個類中,一切由你決定。
你能在任何時候把自己作為一個XMPPStream的 delegate 添加 / 刪除。
[xmppStream ? addDelegate:self ? ?delegateQueue:dispatch_get_main_queue()];...
[xmppStream ? removeDelegate:self];
關于多播代理的更多細節(jié) here? ??關于線程和隊列的更多細節(jié) here
Adding Modules
框架中附帶許多拓展,當然,你想寫多少就寫多少。我們不可能 review 所有拓展,但是我們將列舉一些
XMPPReconnect - 如果意外斷連,自動重連流
XMPPRoster - provides support for standard xmpp roster.
XMPPRoom - provides multi-user chat support.
XMPPPubSub - Publish subscribe
例如,我們將接入 XMPPReconnect 到我們的流中
xmppReconnect = [ [XMPPReconnect ? alloc] ? init];
// xmppReconnect 的可選配置寫這兒
// The defaults are fine for our purposes.
[xmppReconnect ? activate:xmppStream];
// 你也可以選擇性的為模塊增加 delegates
[xmppReconnect ? addDelegate:self ? delegateQueue:dispatch_get_main_queue()];
// 這就是所有需要做的
// 從 xmpp 流,模塊將自動獲得任何它需要的 delegate 方法,同時繼續(xù)做它的事情。除非失效。
Connecting
當你準備好了,你可以開始連接過程:
NSError *error = nil;
if ?( ![xmppStream ? connect:&error] ) ??{
? ? ? NSLog(@"Oops, I probably forgot something:%@", error);
}
如果你忘記設置必要的屬性,如 myJID,之后連接方法將返回 NO,同時 error 信息將通知你。
在連接過程中,客戶端和服務器將經(jīng)歷 xmpp 握手。其中,服務器通知客戶端多種協(xié)議,有它支持的,也有要求的。一些服務器可能要求通過 SSL/TLS (startTLS) 安全連接。如果是這樣的話,xmppStream 將自動安全連接。如果你連接服務器,用不合適的 X509 證書,你可能需要實現(xiàn)xmppStream:willSecureWithSettings: 代理方法來警告默認安全設置。
Authenticating
在所有連接握手完成之后,xmppStreamDidConnect: 代理方法被調(diào)用。這是一般大多數(shù)客戶端應該開始驗證過程的地方。很簡單:
- (void)xmppStreamDidConnect:(XMPPStream *)sender ?{ ?
? ? ?[xmppStream ? authenticateWithPassword:password ? error:NULL];
}
XMPP Logging
通過 xmpp 框架的 logging 有幾個目的:
必須支持幾個 log 等級
不是所有 log 信息都有相同的優(yōu)先級。有些關于 errors,而有些只是信息。levels 幫助開發(fā)者保持他們的日志信息完整,無障礙的打開關閉它們的能力。
必須基于每個文件可配置
必須對最終用戶可配置
xmpp framework 用專業(yè) log 框架:CocoaLumberjack,特別厲害。
這里有你需要知道的關于 XMPPFramework 如何 logging
框架中大多數(shù)文件的頭部,會發(fā)現(xiàn):
// Log levels: off, error, warn, info,?verbose
static ?const ?int ?xmppLogLevel = XMPP_LOG_LEVEL_WARN;
看到了吧,有4種 log levels (還有 XMPP_LOG_LEVEL_NONE)
Error
Warning
Info
Verbose
你能改變?nèi)魏挝募?log level 來獲得更多信息。
此外,有一個 Trace flag 可以用,當 enabled,將打印被調(diào)用的方法。
記住,tracing獨立于 log levels,如,同時設置:
// Log levels: off, error, warn, info, verbose
static ?const ?int ?xmppLogLevel = XMPP_LOG_LEVEL_WARN | XMPP_LOG_FLAG_TRACE;
就代碼而言,這表示
XMPPLogTrace();? // Enabled - Will spit out "<Filename> : <Methodname>"
XMPPLogError(@"I will get logged");
XMPPLogWarn(@"I will get logged");
XMPPLogInfo(@"I will NOT get logged");
XMPPLogVerbose(@"I will NOT get logged");
此外,XMPPStream有一個可選的,允許你查看 raw XML 被發(fā)送和接受。在 XMPPStream.m 中打開:
// Log levels: off, error, warn, info, verbose
static? const? int? xmppLogLevel = XMPP_LOG_LEVEL_INFO | XMPP_LOG_FLAG_SEND_RECV;
回調(diào)所有 logging 的目的是讓你控制什么被log和這些log的狀態(tài)。所以當app啟動時,你將配置 lumberjack 框架。對于新手,下面這樣配:in your AppDelegate
#import ?"DDLog.h"
#import ?"DDTTYLogger.h"
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification ?{? ??
? ? ?[DDLog ?addLogger:
? ? ? ? ? ? ? ? ? ?[DDTTYLogger ?sharedInstance] ?withLogLevel:XMPP_LOG_FLAG_SEND_RECV];
}
更多關于 Lumberjack 信息 project page。