XMPP使用 : http://blog.csdn.net/liuhongwei123888/article/details/6840262
XMPP介紹:http://blog.163.com/guomaolin_gavin/blog/static/19961830720125261015351/
XMPP群聊協(xié)議(muc): http://www.cppblog.com/MemoryGarden/category/12633.html
代碼步驟:
1疗我、初始化XMPPStream
_xmppStream = [[XMPPStream alloc] init];
//允許后臺(tái)
_xmppStream.enableBackgroundingOnSocket = YES;
[_xmppStream setHostName:openfire_ip];//主機(jī)ip
[_xmppStream setHostPort:openfire_port];//端口號(hào)
// 設(shè)置回調(diào)
dispatch_queue_t streamQueue=dispatch_queue_create(xmpp_queueStream, DISPATCH_QUEUE_SERIAL);///<消息的queue
[_xmppStream addDelegate:self delegateQueue:streamQueue];
//設(shè)置斷線重連
XMPPReconnect *xmppReconnet=[[XMPPReconnect alloc] init];
[xmppReconnet activate:_xmppStream];
[xmppReconnet addDelegate:self delegateQueue:streamQueue];
2、連接服務(wù)器
-(void) xmppConnect
{
//1.創(chuàng)建JID
XMPPJID *jid = [XMPPJID jidWithUser:@"lizelusdut" domain:MY_DOMAIN resource:@"iPhone"];
//2.把JID添加到xmppSteam中
[self.xmppStream setMyJID:jid];
//xmppStream.myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@liu-lavymatoMacBook-Pro.local",myJID]];
//連接服務(wù)器南捂,回調(diào)xmppStreamDidConnect
NSError *error = nil;
[self.xmppStream connectWithTimeout:10 error:&error];
if (error) {
NSLog(@"連接出錯(cuò):%@",[error localizedDescription]);
}
}
接下來就是一系列依次調(diào)用delegate的方法
xmppStreamWillConnect
socketDidConnect
xmppStreamDidConnect** ****在這個(gè)方法中我們需要調(diào)用:
******[xmppStream authenticateWithPassword:myPassworderror:&error]
3.驗(yàn)證賬號(hào)吴裤,用戶級(jí)的認(rèn)證 一般放在xmppStreamDidConnect這個(gè)回調(diào)內(nèi)
//連接服務(wù)器后的回調(diào),連接后驗(yàn)證回調(diào)
-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
//連接成功后認(rèn)證用戶名和密碼
NSError *error = nil;
[self.xmppStream authenticateWithPassword:@"!@#admin" error:&error];
if (error) {
NSLog(@"認(rèn)證錯(cuò)誤:%@",[error localizedDescription]);
}
}
驗(yàn)證成功:-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{}
驗(yàn)證失斈缃 :-(void)xmppStream:sender didNotAuthenticate:(DDXMLElement *)error{}
4退出并斷開連接(可選)
新建一個(gè) XMPPPresence 對象麦牺,類型為 unavailable,發(fā)送鞭缭!
斷開連接
- (void)disconnect {
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[self.xmppStream sendElement:presence];
[self.xmppStream disconnect];
}
XMPP的回調(diào)列表:當(dāng)接收到 <名稱/> 標(biāo)簽的內(nèi)容時(shí)剖膳,XMPPFramework 框架回調(diào)對應(yīng)名稱方法
//連接服務(wù)器后的回調(diào)
-(void)xmppStreamDidConnect:(XMPPStream *)sender{}
//獲取好友狀態(tài),通過實(shí)現(xiàn)<presence /> 標(biāo)簽 一個(gè) <presence /> 標(biāo)簽的格式一般如下:
<presence from="">
<show>這里是顯示的內(nèi)容<show />
<status>這里是顯示的狀態(tài)<status />
<presence />
presence 的狀態(tài):
available 上線
away 離開
do not disturb 忙碌
unavailable 下線
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence{}
//收到消息的時(shí)候回調(diào) <message /> 根據(jù) XMPP 協(xié)議岭辣,消息體的內(nèi)容存儲(chǔ)在標(biāo)簽 <body /> 內(nèi)
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {}
//獲取好友列表回調(diào) <iq />
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {}
XMPPROOM 回調(diào)
4****聊天室
//初始化聊天室
XMPPJID *roomJID = [XMPPJID jidWithString:ROOM_JID];
xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:self jid:roomJID];
[xmppRoom activate:xmppStream];
[xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
//創(chuàng)建聊天室成功
- (void)xmppRoomDidCreate:(XMPPRoom *)sender{
DDLogInfo(@"%@: %@", THIS_FILE, THIS_METHOD);
}
//加入聊天室吱晒,使用昵稱[xmppRoom joinRoomUsingNickname:@"quack" history:nil];
//獲取聊天室信息
- (void)xmppRoomDidJoin:(XMPPRoom *)sender {
[xmppRoom fetchConfigurationForm];
[xmppRoom fetchBanList];
[xmppRoom fetchMembersList];
[xmppRoom fetchModeratorsList];
}
如果房間存在,會(huì)調(diào)用委托
// 收到禁止名單列表 - (void)xmppRoom:(XMPPRoom *)sender didFetchBanList:(NSArray *)items;
// 收到好友名單列表 - (void)xmppRoom:(XMPPRoom *)sender didFetchMembersList:(NSArray *)items;
// 收到主持人名單列表 - (void)xmppRoom:(XMPPRoom *)sender didFetchModeratorsList:(NSArray *)items;
房間不存在沦童,調(diào)用委托
- (void)xmppRoom:(XMPPRoom *)sender didNotFetchBanList:(XMPPIQ *)iqError;
- (void)xmppRoom:(XMPPRoom *)sender didNotFetchMembersList:(XMPPIQ *)iqError;
- (void)xmppRoom:(XMPPRoom *)sender didNotFetchModeratorsList:(XMPPIQ *)iqError;
離開房間
[xmppRoom deactivate:xmppStream];
XMPPRoomDelegate的其他代理方法
//離開聊天室
- (void)xmppRoomDidLeave:(XMPPRoom *)sender{DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}
//新人加入群聊
- (void)xmppRoom:(XMPPRoom *)sender occupantDidJoin:(XMPPJID *)occupantJID{DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}
//有人退出群聊
- (void)xmppRoom:(XMPPRoom *)sender occupantDidLeave:(XMPPJID *)occupantJID{DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}
//有人在群里發(fā)言
- (void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID{DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}
發(fā)送消息
發(fā)送消息仑濒,我們需要根據(jù) XMPP 協(xié)議,將數(shù)據(jù)放到 <message /> 標(biāo)簽內(nèi)偷遗,例如:
<message type="chat" to="xiaoming@example.com">
<body>Hello World!<body />
<message />
**好友列表**
獲取 roster 需要客戶端發(fā)送 <iq /> 標(biāo)簽向 XMPP 服務(wù)器端查詢
一個(gè) IQ 請求:
<iq type="get"
from="xiaoming@example.com"
to="example.com"
id="1234567">
<query xmlns="jabber:iq:roster"/>
<iq />
type 屬性墩瞳,說明了該 iq 的類型為 get,與 HTTP 類似氏豌,向服務(wù)器端請求信息
from 屬性喉酌,消息來源,這里是你的 JID
to 屬性泵喘,消息目標(biāo)瞭吃,這里是服務(wù)器域名
id 屬性,標(biāo)記該請求 ID涣旨,當(dāng)服務(wù)器處理完畢請求 get 類型的 iq 后歪架,響應(yīng)的 result 類型 iq 的 ID 與 請求 iq 的 ID 相同
<query xmlns="jabber:iq:roster"/> 子標(biāo)簽,說明了客戶端需要查詢 roster
一個(gè) IQ 響應(yīng):
<iq type="result"
id="1234567"
to="xiaoming@example.com">
<query xmlns="jabber:iq:roster">
<item jid="xiaoyan@example.com" name="小燕" />
<item jid="xiaoqiang@example.com" name="小強(qiáng)"/>
<query />
<iq />
type 屬性霹陡,說明了該 iq 的類型為 result和蚪,查詢的結(jié)果
<query xmlns="jabber:iq:roster"/> 標(biāo)簽的子標(biāo)簽 <item />,為查詢的子項(xiàng)烹棉,即為 roster
item 標(biāo)簽的屬性攒霹,包含好友的 JID,和其它可選的屬性浆洗,例如昵稱等催束。
XMPP消息格式XMPP中定義了 3個(gè)頂層XML元素: Message、Presence伏社、IQ抠刺,下面針對這三種元素進(jìn)行介紹塔淤。
<Message>
?送信息。Jsm(jabber會(huì)話管理器)負(fù)責(zé)滿足所有的消息速妖,不管目標(biāo)用戶的狀態(tài)如何高蜂。如果用戶在線jsm立即提交;否則jsm就存儲(chǔ)。
To :標(biāo)識(shí)消息的接收方罕容。
from : 指發(fā)送方的名字或標(biāo)示(id)o
Text: 此元素包含了要提交給目標(biāo)用戶的信息备恤。
結(jié)構(gòu)如下所示:
<message to= ‘lily@jabber.org/contact’ type =’chat’>
<body> 你好,在忙嗎</body>
</message>
<Presence>
用來表明用戶的狀態(tài)锦秒,如:online露泊、away、dnd(請勿打擾)等旅择。當(dāng)用戶離線或改變自己的狀態(tài)時(shí)滤淳,就會(huì)在stream的上下文中插入一個(gè)Presence元素,來表明自身的狀態(tài).結(jié)構(gòu)如下所示:
<presence>
From =‘lily @ jabber.com/contact’
To = ‘yaoman @ jabber.com/contact'
<status> Online </status>
</presence>
<presence>元素可以取下面幾種值:
Probe :用于向接受消息方法發(fā)送特殊的請求
subscribe:當(dāng)接受方狀態(tài)改變時(shí)砌左,自動(dòng)向發(fā)送方發(fā)送presence信息脖咐。
< IQ >
一種請求/響應(yīng)機(jī)制,從一個(gè)實(shí)體從發(fā)送請求汇歹,另外一個(gè)實(shí)體接受請求屁擅,并進(jìn)行響應(yīng).例如,client在stream的上下文中插入一個(gè)元素产弹,向Server請求得到自己的好友列表派歌,Server返回一個(gè),里面是請求的結(jié)果.
<iq > 主要的屬性是type痰哨。包括:
Get :獲取當(dāng)前域值胶果。
Set :設(shè)置或替換get查詢的值。
Result :說明成功的響應(yīng)了先前的查詢斤斧。
Error: 查詢和響應(yīng)中出現(xiàn)的錯(cuò)誤早抠。
結(jié)構(gòu)如下所示:
<iq from =‘lily @ jabber.com/contact’id=’1364564666’ Type=’result’>
一個(gè) IQ 請求:
<iq type="get"
from="xiaoming@example.com"
to="example.com"
id="1234567">
<query xmlns="jabber:iq:roster"/>
<iq />
type 屬性,說明了該 iq 的類型為 get撬讽,與 HTTP 類似蕊连,向服務(wù)器端請求信息
from 屬性,消息來源游昼,這里是你的 JID
to 屬性甘苍,消息目標(biāo),這里是服務(wù)器域名
id 屬性烘豌,標(biāo)記該請求 ID载庭,當(dāng)服務(wù)器處理完畢請求 get 類型的 iq 后,響應(yīng)的 result 類型 iq 的 ID 與 請求 iq 的 ID 相同
<query xmlns="jabber:iq:roster"/> 子標(biāo)簽,說明了客戶端需要查詢 roster
一個(gè) IQ 響應(yīng):
<iq type="result"
id="1234567"
to="xiaoming@example.com">
<query xmlns="jabber:iq:roster">
<item jid="xiaoyan@example.com" name="小燕" />
<item jid="xiaoqiang@example.com" name="小強(qiáng)"/>
<query />
<iq />
type 屬性囚聚,說明了該 iq 的類型為 result靖榕,查詢的結(jié)果
<query xmlns="jabber:iq:roster"/> 標(biāo)簽的子標(biāo)簽 <item />,為查詢的子項(xiàng)靡挥,即為 roster
item 標(biāo)簽的屬性序矩,包含好友的 JID鸯绿,和其它可選的屬性跋破,例如昵稱等。
XMPP節(jié)點(diǎn)創(chuàng)建
NSXMLElement *get=[NSXMLElement elementWithName:@"iq”];
//<iq ></iq>
[get addAttributeWithName:@"id" stringValue:getRoomMessageId];
//<iq id='F4Krv-5' ></iq>
[get addAttributeWithName:@"to" stringValue:[NSString stringWithFormat:@"conference.%@",openFireNameStr]];
//<iq id='F4Krv-5' to='conference.li726-26'></iq>
[get addAttributeWithName:@"type" stringValue:@"get"];
//<iq id='F4Krv-5' to='conference.li726-26' type='get'></iq>
NSXMLElement *queryXml=[NSXMLElement elementWithName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"];
[get addChild:queryXml];
//<iq id='F4Krv-5' to='conference.li726-26' type='get'><query xmlns='http://jabber.org/protocol/disco#items'></query></iq>
新建或者獲取<> 用elementWithName
新建<name>節(jié)點(diǎn) [NSXMLElement elementWithName:@“name”];
獲取<name>節(jié)點(diǎn) [father elementWithName:@“name” //可以有其他參數(shù)];
<>節(jié)點(diǎn)內(nèi)添加元素 [iq addAttributeWithName:@"id" stringValue:@“1234”];
<iq></iq>———><iq id=“1234” ></iq>
<>節(jié)點(diǎn)內(nèi)元素獲取 str==[[iq attributeForName:@"id"] stringValue:@“1234”];
//str變成@“1234”
子節(jié)點(diǎn)賦值
[iq setStringValue:@“1234”];
<iq>1234</iq>
簡介:
1瓶蝴、XMPP是可擴(kuò)展消息與存在協(xié)議毒返,主要用于im。
2舷手、他是一種類似于http協(xié)議的數(shù)據(jù)傳輸協(xié)議拧簸,過程如:“解包裝—>包裝”過程。
3男窟、在XMPP中盆赤,有三個(gè)角色:客戶端,服務(wù)器歉眷,網(wǎng)關(guān)牺六。 在三者之間可以進(jìn)行任意兩兩通信。服務(wù)器承擔(dān)客戶端信息記錄汗捡,連接管理和信息的路由功能淑际。網(wǎng)關(guān)承擔(dān)與異構(gòu)即時(shí)通信系統(tǒng)的互聯(lián)互通。
4扇住、XMPP的基本網(wǎng)絡(luò)形式是單客戶端通過TCP/IP連接到單服務(wù)器春缕,然后傳輸XML。
5艘蹋、他是基于C/S結(jié)構(gòu)的锄贼,分布式網(wǎng)絡(luò),使用xml的數(shù)據(jù)格式女阀。
6咱娶、XMPP的核心部分是由他的節(jié)構(gòu)成的。
7强品、xmpp網(wǎng)絡(luò):服務(wù)器膘侮,客戶端,組件的榛,插件琼了。
8、xmpp的jid與電子郵件地址類似。節(jié)點(diǎn)雕薪、域昧诱、資源。
9所袁、xmpp主詞匯表有3種節(jié):<message>(用于在實(shí)體間交換“發(fā)后不管”消息)<presence>(傳達(dá)出席狀態(tài)變化并用來操縱出息訂閱)<iq>(提供類似http的get和post操作的請求響應(yīng)語義盏档。).
10、xmpp會(huì)話:連接燥爷、流的建立、身份驗(yàn)證前翎、會(huì)話正文、斷開連接道川。
基本工作原理:
從一個(gè)client到另一個(gè)client的jabber消息和數(shù)據(jù)都要通過xmpp server。
1.client連接到server立宜。
2.server 利用本地目錄系統(tǒng)的證書對其認(rèn)證。
3.client制定目標(biāo)地址橙数,讓server告知目標(biāo)狀態(tài)。
4.server查找商模,鏈接并進(jìn)行相互認(rèn)證奠旺。
5.client間進(jìn)行交互。
XMPP****節(jié):
核心節(jié):<message><presene><iq>
1响疚、<stream> xmpp以其標(biāo)記開始瞪醋。
2、<presence>用來表明用戶狀態(tài)践盼”鑫。可以來廣播或“發(fā)布-訂閱”;<status>網(wǎng)絡(luò)狀態(tài)肄程、<show>可用狀態(tài)、<priority>資源優(yōu)先級(jí)玄叠。
3拓提、<iq>一種請求/響應(yīng)機(jī)制。
4寺惫、<message>用于兩個(gè)jabber用戶發(fā)送消息胆数。<body>是消息內(nèi)容必尼;他包含<subject/>(消息標(biāo)題)<body/>(消息內(nèi)容)<thread/>(跟蹤會(huì)話線索)子標(biāo)簽。
簡單會(huì)話:
<stream:stream> 創(chuàng)建一個(gè)xmpp流
<iq type=’get’> 請求elizabeth的花名冊判莉,也就是她的所有已存儲(chǔ)的聯(lián)系人列表育谬。
<query xmlns=’jabber:iq:roster’/>
</iq>
<presence/> 通知服務(wù)器她已經(jīng)在線并可以訪問膛檀。 當(dāng)他注意到darcy在線的時(shí)候,就會(huì)發(fā)個(gè)message節(jié)咖刃,
<message to=’darcy@pemberley.lib’
from=’ellizabaeth@longbourn.lit/ballroom’
type=’chat’>
<body>sdf</body>
</message>
<presence type=’unavailable’/> 告訴服務(wù)器嚎杨,這是不可訪問的要關(guān)閉
</stream:stream>
節(jié)屬性:
支持通用屬性:from围苫,to,type箩帚,id。
1)盔然、from
識(shí)別此節(jié)的起始jid。這里不建議在輸出的節(jié)上手工設(shè)置from屬性油额,服務(wù)器會(huì)在這些節(jié)通過時(shí)添加正確的from屬性刻帚,而如果錯(cuò)誤地設(shè)置from屬性會(huì)導(dǎo)致服務(wù)器拒絕整個(gè)節(jié)。
客戶端-服務(wù)器中掂僵,接收到的節(jié)上沒有from屬性顷歌,意味著該節(jié)來源于服務(wù)器自身,而在服務(wù)器-服務(wù)器中芹扭,缺少from被視為是錯(cuò)誤舱卡。
2)队萤、to
把xml節(jié)發(fā)送到to屬性指定的jid。他和from相似舍杜。
客戶端-服務(wù)器流中沒有to屬性赵辕,那么服務(wù)器將假設(shè)它是有意發(fā)給服務(wù)器自身的消息匆帚,建議在向服務(wù)器自身發(fā)消息時(shí)忽略to。
如果to屬性中指定的jid是一個(gè)用戶互拾,那么服務(wù)器有可能代表用戶來處理該節(jié)嚎幸。
如果目的地是一個(gè)裸jid,那么服務(wù)器將處理這個(gè)節(jié)嫉晶。
如果目的地是一個(gè)完整的jid田篇,那么服務(wù)器將直接把該節(jié)路由到該用戶箍铭。
3)诈火、type
這個(gè)屬性指定了三個(gè)節(jié)的具體類型。
三個(gè)節(jié)都可以把type設(shè)置為error刀崖,表示這個(gè)節(jié)是對已接收到的同一類型的節(jié)的錯(cuò)誤影響拍摇,不要響應(yīng)類型為error的節(jié)充活,避免在網(wǎng)絡(luò)上出線反饋環(huán)節(jié)。
4)巡语、id
給節(jié)指定id來輔助識(shí)別響應(yīng)淮菠。對于iq節(jié)合陵,id是必須的澄阳,但是對于其他的節(jié)id是可選的碎赢。如果某個(gè)節(jié)是為了響應(yīng)一個(gè)攜帶id屬性的節(jié)而產(chǎn)生的,那么這個(gè)應(yīng)答必須包含攜帶相同值得id值襟齿。
id必須具有唯一性枕赵,這樣節(jié)的發(fā)送者就可以使用它來甄別響應(yīng)了拷窜。最簡單的做法就是讓id屬性值在給定的流中保持唯一性涧黄,以免歧義笋妥。
在message和presence節(jié)的應(yīng)答節(jié)一般僅限于報(bào)告錯(cuò)誤窄潭,iq的應(yīng)答節(jié)可以用來通知成功操作、確認(rèn)命令或返回請求的數(shù)據(jù)信认。無論如何客戶端都可以使用應(yīng)答節(jié)的id屬性來識(shí)別與該節(jié)相關(guān)聯(lián)的請求節(jié)嫁赏。 在短時(shí)間內(nèi)發(fā)送大量同類型的節(jié)油挥,此時(shí)這個(gè)功能就非常關(guān)鍵了深寥。因?yàn)檫@些節(jié)的應(yīng)答可能會(huì)以亂序形式到達(dá)。
節(jié):
1)则酝、presence
他控制并報(bào)告實(shí)體的可訪問性闰集。(包括:在線,離線爽雄; 離開挚瘟,請勿打擾等饲梭。 ) 他還可以用來建立和終止向其他實(shí)體發(fā)布出席訂閱排拷。
有了出席訂閱通知,我們在即時(shí)通信系統(tǒng)中就可以在發(fā)送消息之前知道接收者是否在線布蔗。
(1)、普通的presence
此時(shí)他是不包含type屬性的顿乒,如果有的話他的屬性值為unavailable活著error泽谨。 在這里,type屬性是沒有available值得骨杂,因?yàn)槲覀兛梢酝ㄟ^缺省的type來設(shè)定雄卷。
用戶可以通過發(fā)送不攜帶to屬性丁鹉,并直接發(fā)往服務(wù)器的presence節(jié)來操縱出席狀態(tài)。如下:
<presence/> 前兩個(gè)節(jié)將用戶的出息狀態(tài)設(shè)置為在線和離線
<presence type=‘unavailable’/> 離線
<presence>
<show>away</show> 只能用在presence中雳灾,值away離開冯凹,chat聊天谈竿,end不希望被打擾空凸,xa長期離開寸痢, 傳達(dá)用戶可訪問性的性質(zhì),它請求接收者的客戶端使用這個(gè)消息來更新發(fā)送者出息狀態(tài)的可視化指示器道逗。
<status>sf</status> 一個(gè)人們可讀的字符串滓窍,用戶可以將其設(shè)置為能夠傳達(dá)出席信息的任何值巩那。 聊天時(shí),接收者的客戶端中這個(gè)字符串一般緊挨著聯(lián)系人名字顯示噪生。
</presence>
<presence>
<status>sfdf</status>
<priority>22</priority> 優(yōu)先級(jí) 同時(shí)具有多個(gè)回話的用戶可以使用優(yōu)先級(jí)來指出哪一個(gè)資源應(yīng)該接收到那些發(fā)往該用戶裸jid的聊天消息跺嗽。
</presence>
<presence>
<prioriry>11</pritority>
</presence>
(2)、擴(kuò)展presence
比如將你正在聽歌植兰,心情等信息廣播給其他聯(lián)系人钉跷。這里用流量較大肚逸。
(3)朦促、出席訂閱
server會(huì)自動(dòng)將出席信息廣播給聯(lián)系人,用戶也會(huì)從所有他已經(jīng)進(jìn)行出席訂閱的聯(lián)系人那里接收到出席的狀態(tài)更新血当。
對于好友狀態(tài)的訂閱:A訂閱了B得出席信息臊旭,這里并不是說B也訂閱了A得出席信息箩退。
訂閱狀態(tài):subscribe(建立訂閱)戴涝,unsubscribe(取消訂閱),subscribed(應(yīng)答建立)奸鸯,unsubscribed(應(yīng)答取消)娄涩。
AB訂閱:
<presence from=‘a(chǎn)@longbourn.lit/outside’ to=‘b@pemberley.lit’ type=‘subscribe’/>
<presence from=‘b@pemberley.lit/library’ to=‘a(chǎn)@longbourn.lit/outside’ type=‘subscribed’/>
<presence from=‘b@pemberley.lit/library’ to=‘a(chǎn)@longbourn.lit’ type=‘subscribe’/>
<presence from=‘a(chǎn)@longbourn.lit/outside’ to=‘b@pemberley.lit/library’ type=‘subscribed’/>
(4)映跟、定向出席
他是一種直接發(fā)給另一個(gè)用戶或其他某個(gè)實(shí)體的普通presence節(jié)。這里可以用來向那些沒有進(jìn)行出席訂閱的實(shí)體傳送出席狀態(tài)信息孔轴。也就是臨時(shí)出席碎捺。
這里當(dāng)發(fā)送者變成不可訪問的狀態(tài)的時(shí)候收厨,出席信息的接收者將會(huì)自動(dòng)得到通知,即使發(fā)送者忘記顯示的通知接收者雁竞。這里可以使用定向出席來臨時(shí)地掌握某個(gè)用戶的可訪問性拧额。
2)侥锦、message
從一端到另一端發(fā)送消息恭垦。這個(gè)節(jié)屬于發(fā)出后不再過問,可靠性不能保證唠帝。一旦消息發(fā)出去了玄柏,發(fā)送者就不會(huì)知道他是不是傳送出去了禁荸,也不會(huì)知道到達(dá)的時(shí)間。
message示例:
單人聊天
<message from=‘a(chǎn)@netherfield.lit/frawing_room’ to=‘b@pemberley.lit’ type=‘chat’>
<body>adf</body>
</message>
多人聊天
benlent夫人向聊天室bennets@chat.merython.lit發(fā)送消息,bennet接收消息
<message from=’bennets@chat.merython.lit/mrs.bennet’ to=‘mr.bennet@longbourn.lit/study’ type=‘groupchat’>
<body>df</body>
</message>
(1)映砖、消息類型
type指出:chat(一對一聊天)邑退,error地技,normal,group chat(多人聊天)飒硅,headline(不支持或者不方便應(yīng)答的自動(dòng)化服務(wù)使用)作谚。
type是可以省略的妹懒,默認(rèn)為normal,但是我們應(yīng)該提供一個(gè)type值会前,
(2)瓦宜、消息內(nèi)容
<body>元素包含著該消息中人們的可讀的內(nèi)容搂橙。只要有不同的xml:lang屬性就可以使用多個(gè)<body>区转。
<thread>元素用來創(chuàng)建線索废离,他的內(nèi)容是一個(gè)用來區(qū)分不同線索的唯一標(biāo)識(shí)符。應(yīng)答節(jié)應(yīng)該包含與所應(yīng)答的節(jié)相同的<thread>元素悼尾。 (線索:向電子郵件一樣)
在消息中闺魏,可以使用XHTML-IM來給消息提供格式化俯画,超鏈接,以及富媒體泡仗。也可以使用Chat State Notifications來允許用戶通告對方自己正在撰寫消息或有空娩怎。(qq的正在輸入)
3)截亦、iq
這個(gè)節(jié)表示的時(shí)info/query(信息與查詢),他給xmpp童心提供請求和響應(yīng)機(jī)制急灭。和http的基本工作原理想死葬馋,允許獲取和設(shè)置查詢肾扰。(get 和 post)
每個(gè)節(jié)都需要有一個(gè)響應(yīng)集晚,但是這個(gè)節(jié)的必須的id將用來把響應(yīng)與導(dǎo)致該響應(yīng)的請求關(guān)聯(lián)起來。
type:get蒋院,set請求節(jié)欺旧; result蛤签,error為響應(yīng)節(jié)震肮。
下面看示例戳晌,每個(gè)iq節(jié)必須匹配id屬性
a向服務(wù)器發(fā)送了一個(gè)格式錯(cuò)誤的花名冊請求
<iq from=a@longbourn.lit/garden’ type=‘get’ id=‘roster1’>
<query cmlns=‘jabber:iq:roster’/>
</iq>
<iq to=‘a(chǎn)@longbourn.lit/garden’ type=‘error’ id=‘roster1’>
<query xmlns=‘jabber:iq:roster’/>
<error type=‘cancel’>
<feature-not-implemented xmlns=‘urn:ietf:params:xml:ns:xmpp-stanzas’/>
</error>
</iq>
重新發(fā)送
<iq from=a@longbourn.lit/garden’ type=‘get’ id=‘roster2’>
<query cmlns=‘jabber:iq:roster’/>
</iq>
<iq to=‘a(chǎn)@longbourn.lit/garden’ type=‘result’ id=‘roster2’>
<query xmlns=‘jabber:iq:roster’>
<item jid=‘b@longbourn.lit’ name=‘b’/>
<item jid=‘c@netherfield.lit’ name=‘c’/>
</query>
</iq>
a將b添加到花名冊,回復(fù)空白iq來應(yīng)答成功沦偎。
<iq from=‘a(chǎn)@longbourn.lit/garden’ type=‘set’ id=‘roster3’>
<query xmlns=‘jabber:iq:roster’>
<item jid=“b@pemberley.lit’ name=‘b’/>
</query>
</iq>
<iq to=‘a(chǎn)@longbourn.lit/garden’ type=‘result’ id=‘roster3’/>
4)扛施、error
在錯(cuò)誤提示節(jié)中,必須將type設(shè)置為error匙奴,并且需要攜帶一個(gè)<error>子元素泼菌。
在error中啦租,他的type類型為:cancel(不應(yīng)該重試)篷角,continue(警告信息)恳蹲,modify(發(fā)送的數(shù)據(jù)需要一些修改才可以被接受),auth(通知實(shí)體在以某種方式進(jìn)行身份驗(yàn)證之后重試)贺奠,wait(報(bào)告server臨時(shí)遇到問題儡率,稍后重發(fā))以清。
在<error>中玖媚,必須包含一個(gè)錯(cuò)誤條件作為他的子元素今魔,也可以在<error>元素的子元素中指定應(yīng)用程序的特定錯(cuò)誤條件错森。還可以包含一個(gè)<text>元素來進(jìn)一步指出有關(guān)該錯(cuò)誤的詳細(xì)信息。
要注意的是每個(gè)錯(cuò)誤條件元素都必須位于urn:ietf:params:xml:ns:xmpp-stanzas命名空間里殃姓。
<error type=‘cancel’>
<not-allowed xmlns=‘urn:ietf:params:xml:ns:xmpp-stanzas’/> 這里指出了一般性故障
<closed-node xmlns=‘http:/jabber.org/protocol/pubsub#errors’/> 給出了請缺德應(yīng)用程序錯(cuò)誤提示信息
<text xmlns=‘urn:ietf:params:xml:ns:xmpp-stanzas>dfs</text> 包含了問題描述
</error>
XMPP****尋址:
xmpp網(wǎng)絡(luò)有一個(gè)或多個(gè)地址jid蜗侈, a@aaa.llit 組成:節(jié)點(diǎn)踏幻、域、資源(帶有資源的jid是完整jid夭苗,沒有資源的jid是裸jid)题造,其中節(jié)點(diǎn)和資源是可選的界赔,域是必選的须妻。
其中域是服務(wù)器等的可解析dns名稱荒吏。只有域組成的jid是有效的地址,表示服務(wù)器的地址瞧挤。
其中指向域的節(jié)將由服務(wù)器自身處理特恬,并且可能被路由到其他的組件或者插件上徐钠。
在本地時(shí)我們通常會(huì)識(shí)別域中的一個(gè)特定的用戶尝丐,它位于@之前爹袁,本地部分還可以用來識(shí)別其他對象失息,多人聊天服務(wù)將每個(gè)聊天室顯示為一個(gè)jid档址,節(jié)點(diǎn)部分指向聊天室。
jid的資源部分會(huì)標(biāo)識(shí)一個(gè)特定的客戶端xmpp鏈接邻梆,對于xmpp客戶端來說守伸,每個(gè)鏈接均被指派一個(gè)資源,如 用 a@aaa.lit/study和a@aaa.lit/library 來尋址确虱,其中資源部分也可以用來識(shí)別其他對象含友,在多人聊天時(shí),jid的資源被用來識(shí)別聊天室中的一個(gè)特定的用戶校辩。
客戶端處理裸jid的時(shí)候,服務(wù)器自己將處理發(fā)往客戶端裸jid的節(jié)宜咒。如:一條發(fā)往某個(gè)客戶端的裸jid的消息將被轉(zhuǎn)發(fā)到該用戶的一個(gè)或多個(gè)已連接資源,如果該用戶離線把鉴,那么就將該消息存儲(chǔ)以后傳送故黑。但是發(fā)給完整jid的節(jié)通常會(huì)直接路由到該資源所在的客戶端連接⊥タ常可以將裸jid視為尋址用戶的賬戶场晶,而不是尋址該用戶的某個(gè)已連接的客戶端。
xmpp****連接:
連接怠缸,流的建立诗轻,身份驗(yàn)證以及斷開連接。
1).連接
發(fā)送節(jié)前要建立xmpp流揭北,在流存在之前要建立通往xmpp服務(wù)器的連接扳炬。
客戶端和服務(wù)器利用域名系統(tǒng)將服務(wù)器的域名解析成一個(gè)能夠連接的地址。電子郵件服務(wù)特別的使用郵件交換臺(tái)記錄來提供處理特定域郵件的服務(wù)器列表搔体。這樣一個(gè)知名服務(wù)器地址就不用處理每一項(xiàng)服務(wù)請求了恨樟。電子郵件在dns中有特殊的對待。現(xiàn)在服務(wù)記錄srv可用來為任意服務(wù)提供類似的功能疚俱。
當(dāng)xmpp客戶端或服務(wù)器連接到另一個(gè)xmpp服務(wù)器的時(shí)候劝术,首先要在服務(wù)器域中查詢適當(dāng)?shù)膕rv記錄。查詢應(yīng)答中可能包含多條srv記錄呆奕,這樣就可以在多臺(tái)服務(wù)器間建立負(fù)載均衡鏈接养晋。
當(dāng)沒有找到合適的srv記錄的時(shí)候,應(yīng)用程序試著直接連接到給定域登馒。大多數(shù)庫也可以顯式制定要連接的服務(wù)器匙握。
2).流的建立
向服務(wù)器發(fā)送起始元素<stream:stream>,就可以打開xmpp流陈轿。服務(wù)器通過發(fā)送響應(yīng)流的起始標(biāo)記<stream:stream>進(jìn)行響應(yīng)圈纺。
服務(wù)器先發(fā)送<stream:features>元素秦忿,詳細(xì)列舉xmpp流中支持的所有功能。這些功能大多數(shù)與可用的加密和身份驗(yàn)證選項(xiàng)有關(guān)蛾娶。
客戶端發(fā)給服務(wù)器
<?xml version=’1.0′?>
<stream:stream xmlns=’jabber:client’
xmlns:straem=’http://ethrx.jabber.org/streams’
version=’1.0′
to=’pemberley.lit’>
服務(wù)器應(yīng)答
<?xml version=’1.0′?>
<stream:stream xmlns=’jabber:client’
xmlns:stream=’http://etherx.jabber.org/streams’
version=’1.0′
from=’pemberley.lit’
id=’dddd’
xml:lang=’en’>
<stream:features>
<stream:freatures>
<starttls xmlns=’urn:ietf:params:xml:ns:xmpp-tls’/>
<compression xmlns=’http://jabber.org/features/compress’>
<method>zlib</method>
</compression>
<mechanisms xmlns=’urn:ietf:params:xml:ns:xmpp-sasl’> <mechanism>DIGEST-MD5</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
</stream:features>
根據(jù)數(shù)據(jù)交換信息指導(dǎo)pemberley.org服務(wù)器支持TLS灯谣,流壓縮zlib等。
在兩臺(tái)服務(wù)器間建立xmpp流的過程相同蛔琅,但是 jabber:client換成 jabber:server才可以胎许。
3).身份驗(yàn)證
xmpp可以進(jìn)行tls傳輸層安全加密,并且大多數(shù)客戶端默認(rèn)使用罗售。服務(wù)器支持tls加密后辜窑,客戶端就會(huì)啟動(dòng)tls鏈接,并將當(dāng)前套接字升級(jí)為一個(gè)加密套接字寨躁。創(chuàng)建一對新的xmpp流穆碎。
xmpp身份驗(yàn)證使用sasl 簡單身份驗(yàn)證與安全層協(xié)議,并支持多種身份驗(yàn)證機(jī)制职恳。服務(wù)器通提供明文驗(yàn)證和基于md5摘要的驗(yàn)證所禀,但是某些服務(wù)器還支持通過kerberos或特殊令牌來驗(yàn)證。
完成身份驗(yàn)證后放钦,客戶端必選為該鏈接綁定一個(gè)資源并啟動(dòng)一個(gè)會(huì)話色徘。如果用戶正在線路上查看xmpp流量,就會(huì)看到<bind><session>元素被發(fā)送出去操禀。(在<iq>中) 如果客戶端沒有提供綁定的資源褂策,那么服務(wù)器將為其選定一個(gè)。
當(dāng)兩臺(tái)服務(wù)器相互連接的時(shí)候床蜘,服務(wù)器交換并驗(yàn)證tls證書辙培,或者接受服務(wù)器使用某種回?fù)軈f(xié)議通過dns來驗(yàn)證發(fā)送者身份。
4).連接斷開
當(dāng)用戶結(jié)束xmpp會(huì)話的時(shí)候邢锯,他們終止會(huì)話并斷開連接扬蕊。最有禮貌的終止會(huì)話的方式是:先發(fā)送無效出席信息,然后關(guān)閉<stream:stream>元素丹擎。
通過發(fā)送最后的無效出席信息尾抑,用戶的聯(lián)系人能夠得知該用戶離開的原因。
<presence type=’unavailable’/>
</stream:stream>
然后蒂培,服務(wù)器終止發(fā)往客戶端的流再愈。