XMPP使用 : http://blog.csdn.net/liuhongwei123888/article/details/6840262
XMPP介紹:http://blog.163.com/guomaolin_gavin/blog/static/19961830720125261015351/
XMPP群聊協議(muc): http://www.cppblog.com/MemoryGarden/category/12633.html
代碼步驟:
1、初始化XMPPStream
_xmppStream = [[XMPPStream alloc] init];
//允許后臺
_xmppStream.enableBackgroundingOnSocket = YES;
[_xmppStream setHostName:openfire_ip];//主機ip
[_xmppStream setHostPort:openfire_port];//端口號
// 設置回調
dispatch_queue_t streamQueue=dispatch_queue_create(xmpp_queueStream, DISPATCH_QUEUE_SERIAL);///<消息的queue
[_xmppStream addDelegate:self delegateQueue:streamQueue];
//設置斷線重連
XMPPReconnect *xmppReconnet=[[XMPPReconnect alloc] init];
[xmppReconnet activate:_xmppStream];
[xmppReconnet addDelegate:self delegateQueue:streamQueue];
2、連接服務器
-(void) xmppConnect
{
//1.創建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]];
//連接服務器,回調xmppStreamDidConnect
NSError *error = nil;
[self.xmppStream connectWithTimeout:10 error:&error];
if (error) {
NSLog(@"連接出錯:%@",[error localizedDescription]);
}
}
接下來就是一系列依次調用delegate的方法
xmppStreamWillConnect
socketDidConnect
xmppStreamDidConnect** ****在這個方法中我們需要調用:
******[xmppStream authenticateWithPassword:myPassworderror:&error]
3.驗證賬號,用戶級的認證 一般放在xmppStreamDidConnect這個回調內
//連接服務器后的回調,連接后驗證回調
-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
//連接成功后認證用戶名和密碼
NSError *error = nil;
[self.xmppStream authenticateWithPassword:@"!@#admin" error:&error];
if (error) {
NSLog(@"認證錯誤:%@",[error localizedDescription]);
}
}
驗證成功:-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{}
驗證失敗:-(void)xmppStream:sender didNotAuthenticate:(DDXMLElement *)error{}
4退出并斷開連接(可選)
新建一個 XMPPPresence 對象,類型為 unavailable,發送!
斷開連接
- (void)disconnect {
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[self.xmppStream sendElement:presence];
[self.xmppStream disconnect];
}
XMPP的回調列表:當接收到 <名稱/> 標簽的內容時,XMPPFramework 框架回調對應名稱方法
//連接服務器后的回調
-(void)xmppStreamDidConnect:(XMPPStream *)sender{}
//獲取好友狀態,通過實現<presence /> 標簽 一個 <presence /> 標簽的格式一般如下:
<presence from="">
<show>這里是顯示的內容<show />
<status>這里是顯示的狀態<status />
<presence />
presence 的狀態:
available 上線
away 離開
do not disturb 忙碌
unavailable 下線
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence{}
//收到消息的時候回調 <message /> 根據 XMPP 協議,消息體的內容存儲在標簽 <body /> 內
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {}
//獲取好友列表回調 <iq />
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {}
XMPPROOM 回調
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()];
//創建聊天室成功
- (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];
}
如果房間存在,會調用委托
// 收到禁止名單列表 - (void)xmppRoom:(XMPPRoom *)sender didFetchBanList:(NSArray *)items;
// 收到好友名單列表 - (void)xmppRoom:(XMPPRoom *)sender didFetchMembersList:(NSArray *)items;
// 收到主持人名單列表 - (void)xmppRoom:(XMPPRoom *)sender didFetchModeratorsList:(NSArray *)items;
房間不存在,調用委托
- (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);}
//有人在群里發言
- (void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID{DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}
發送消息
發送消息,我們需要根據 XMPP 協議,將數據放到 <message /> 標簽內,例如:
<message type="chat" to="xiaoming@example.com">
<body>Hello World!<body />
<message />
**好友列表**
獲取 roster 需要客戶端發送 <iq /> 標簽向 XMPP 服務器端查詢
一個 IQ 請求:
<iq type="get"
from="xiaoming@example.com"
to="example.com"
id="1234567">
<query xmlns="jabber:iq:roster"/>
<iq />
type 屬性,說明了該 iq 的類型為 get,與 HTTP 類似,向服務器端請求信息
from 屬性,消息來源,這里是你的 JID
to 屬性,消息目標,這里是服務器域名
id 屬性,標記該請求 ID,當服務器處理完畢請求 get 類型的 iq 后,響應的 result 類型 iq 的 ID 與 請求 iq 的 ID 相同
<query xmlns="jabber:iq:roster"/> 子標簽,說明了客戶端需要查詢 roster
一個 IQ 響應:
<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="小強"/>
<query />
<iq />
type 屬性,說明了該 iq 的類型為 result,查詢的結果
<query xmlns="jabber:iq:roster"/> 標簽的子標簽 <item />,為查詢的子項,即為 roster
item 標簽的屬性,包含好友的 JID,和其它可選的屬性,例如昵稱等。
XMPP消息格式XMPP中定義了 3個頂層XML元素: Message、Presence、IQ,下面針對這三種元素進行介紹。
<Message>
?送信息。Jsm(jabber會話管理器)負責滿足所有的消息,不管目標用戶的狀態如何。如果用戶在線jsm立即提交;否則jsm就存儲。
To :標識消息的接收方。
from : 指發送方的名字或標示(id)o
Text: 此元素包含了要提交給目標用戶的信息。
結構如下所示:
<message to= ‘lily@jabber.org/contact’ type =’chat’>
<body> 你好,在忙嗎</body>
</message>
<Presence>
用來表明用戶的狀態,如:online、away、dnd(請勿打擾)等。當用戶離線或改變自己的狀態時,就會在stream的上下文中插入一個Presence元素,來表明自身的狀態.結構如下所示:
<presence>
From =‘lily @ jabber.com/contact’
To = ‘yaoman @ jabber.com/contact'
<status> Online </status>
</presence>
<presence>元素可以取下面幾種值:
Probe :用于向接受消息方法發送特殊的請求
subscribe:當接受方狀態改變時,自動向發送方發送presence信息。
< IQ >
一種請求/響應機制,從一個實體從發送請求,另外一個實體接受請求,并進行響應.例如,client在stream的上下文中插入一個元素,向Server請求得到自己的好友列表,Server返回一個,里面是請求的結果.
<iq > 主要的屬性是type。包括:
Get :獲取當前域值。
Set :設置或替換get查詢的值。
Result :說明成功的響應了先前的查詢。
Error: 查詢和響應中出現的錯誤。
結構如下所示:
<iq from =‘lily @ jabber.com/contact’id=’1364564666’ Type=’result’>
一個 IQ 請求:
<iq type="get"
from="xiaoming@example.com"
to="example.com"
id="1234567">
<query xmlns="jabber:iq:roster"/>
<iq />
type 屬性,說明了該 iq 的類型為 get,與 HTTP 類似,向服務器端請求信息
from 屬性,消息來源,這里是你的 JID
to 屬性,消息目標,這里是服務器域名
id 屬性,標記該請求 ID,當服務器處理完畢請求 get 類型的 iq 后,響應的 result 類型 iq 的 ID 與 請求 iq 的 ID 相同
<query xmlns="jabber:iq:roster"/> 子標簽,說明了客戶端需要查詢 roster
一個 IQ 響應:
<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="小強"/>
<query />
<iq />
type 屬性,說明了該 iq 的類型為 result,查詢的結果
<query xmlns="jabber:iq:roster"/> 標簽的子標簽 <item />,為查詢的子項,即為 roster
item 標簽的屬性,包含好友的 JID,和其它可選的屬性,例如昵稱等。
XMPP節點創建
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>節點 [NSXMLElement elementWithName:@“name”];
獲取<name>節點 [father elementWithName:@“name” //可以有其他參數];
<>節點內添加元素 [iq addAttributeWithName:@"id" stringValue:@“1234”];
<iq></iq>———><iq id=“1234” ></iq>
<>節點內元素獲取 str==[[iq attributeForName:@"id"] stringValue:@“1234”];
//str變成@“1234”
子節點賦值
[iq setStringValue:@“1234”];
<iq>1234</iq>
簡介:
1、XMPP是可擴展消息與存在協議,主要用于im。
2、他是一種類似于http協議的數據傳輸協議,過程如:“解包裝—>包裝”過程。
3、在XMPP中,有三個角色:客戶端,服務器,網關。 在三者之間可以進行任意兩兩通信。服務器承擔客戶端信息記錄,連接管理和信息的路由功能。網關承擔與異構即時通信系統的互聯互通。
4、XMPP的基本網絡形式是單客戶端通過TCP/IP連接到單服務器,然后傳輸XML。
5、他是基于C/S結構的,分布式網絡,使用xml的數據格式。
6、XMPP的核心部分是由他的節構成的。
7、xmpp網絡:服務器,客戶端,組件,插件。
8、xmpp的jid與電子郵件地址類似。節點、域、資源。
9、xmpp主詞匯表有3種節:<message>(用于在實體間交換“發后不管”消息)<presence>(傳達出席狀態變化并用來操縱出息訂閱)<iq>(提供類似http的get和post操作的請求響應語義。).
10、xmpp會話:連接、流的建立、身份驗證、會話正文、斷開連接。
基本工作原理:
從一個client到另一個client的jabber消息和數據都要通過xmpp server。
1.client連接到server。
2.server 利用本地目錄系統的證書對其認證。
3.client制定目標地址,讓server告知目標狀態。
4.server查找,鏈接并進行相互認證。
5.client間進行交互。
XMPP****節:
核心節:<message><presene><iq>
1、<stream> xmpp以其標記開始。
2、<presence>用來表明用戶狀態。可以來廣播或“發布-訂閱”;<status>網絡狀態、<show>可用狀態、<priority>資源優先級。
3、<iq>一種請求/響應機制。
4、<message>用于兩個jabber用戶發送消息。<body>是消息內容;他包含<subject/>(消息標題)<body/>(消息內容)<thread/>(跟蹤會話線索)子標簽。
簡單會話:
<stream:stream> 創建一個xmpp流
<iq type=’get’> 請求elizabeth的花名冊,也就是她的所有已存儲的聯系人列表。
<query xmlns=’jabber:iq:roster’/>
</iq>
<presence/> 通知服務器她已經在線并可以訪問。 當他注意到darcy在線的時候,就會發個message節,
<message to=’darcy@pemberley.lib’
from=’ellizabaeth@longbourn.lit/ballroom’
type=’chat’>
<body>sdf</body>
</message>
<presence type=’unavailable’/> 告訴服務器,這是不可訪問的要關閉
</stream:stream>
節屬性:
支持通用屬性:from,to,type,id。
1)、from
識別此節的起始jid。這里不建議在輸出的節上手工設置from屬性,服務器會在這些節通過時添加正確的from屬性,而如果錯誤地設置from屬性會導致服務器拒絕整個節。
客戶端-服務器中,接收到的節上沒有from屬性,意味著該節來源于服務器自身,而在服務器-服務器中,缺少from被視為是錯誤。
2)、to
把xml節發送到to屬性指定的jid。他和from相似。
客戶端-服務器流中沒有to屬性,那么服務器將假設它是有意發給服務器自身的消息,建議在向服務器自身發消息時忽略to。
如果to屬性中指定的jid是一個用戶,那么服務器有可能代表用戶來處理該節。
如果目的地是一個裸jid,那么服務器將處理這個節。
如果目的地是一個完整的jid,那么服務器將直接把該節路由到該用戶。
3)、type
這個屬性指定了三個節的具體類型。
三個節都可以把type設置為error,表示這個節是對已接收到的同一類型的節的錯誤影響,不要響應類型為error的節,避免在網絡上出線反饋環節。
4)、id
給節指定id來輔助識別響應。對于iq節,id是必須的,但是對于其他的節id是可選的。如果某個節是為了響應一個攜帶id屬性的節而產生的,那么這個應答必須包含攜帶相同值得id值。
id必須具有唯一性,這樣節的發送者就可以使用它來甄別響應了。最簡單的做法就是讓id屬性值在給定的流中保持唯一性,以免歧義。
在message和presence節的應答節一般僅限于報告錯誤,iq的應答節可以用來通知成功操作、確認命令或返回請求的數據。無論如何客戶端都可以使用應答節的id屬性來識別與該節相關聯的請求節。 在短時間內發送大量同類型的節,此時這個功能就非常關鍵了。因為這些節的應答可能會以亂序形式到達。
節:
1)、presence
他控制并報告實體的可訪問性。(包括:在線,離線; 離開,請勿打擾等。 ) 他還可以用來建立和終止向其他實體發布出席訂閱。
有了出席訂閱通知,我們在即時通信系統中就可以在發送消息之前知道接收者是否在線。
(1)、普通的presence
此時他是不包含type屬性的,如果有的話他的屬性值為unavailable活著error。 在這里,type屬性是沒有available值得,因為我們可以通過缺省的type來設定。
用戶可以通過發送不攜帶to屬性,并直接發往服務器的presence節來操縱出席狀態。如下:
<presence/> 前兩個節將用戶的出息狀態設置為在線和離線
<presence type=‘unavailable’/> 離線
<presence>
<show>away</show> 只能用在presence中,值away離開,chat聊天,end不希望被打擾,xa長期離開, 傳達用戶可訪問性的性質,它請求接收者的客戶端使用這個消息來更新發送者出息狀態的可視化指示器。
<status>sf</status> 一個人們可讀的字符串,用戶可以將其設置為能夠傳達出席信息的任何值。 聊天時,接收者的客戶端中這個字符串一般緊挨著聯系人名字顯示。
</presence>
<presence>
<status>sfdf</status>
<priority>22</priority> 優先級 同時具有多個回話的用戶可以使用優先級來指出哪一個資源應該接收到那些發往該用戶裸jid的聊天消息。
</presence>
<presence>
<prioriry>11</pritority>
</presence>
(2)、擴展presence
比如將你正在聽歌,心情等信息廣播給其他聯系人。這里用流量較大。
(3)、出席訂閱
server會自動將出席信息廣播給聯系人,用戶也會從所有他已經進行出席訂閱的聯系人那里接收到出席的狀態更新。
對于好友狀態的訂閱:A訂閱了B得出席信息,這里并不是說B也訂閱了A得出席信息。
訂閱狀態:subscribe(建立訂閱),unsubscribe(取消訂閱),subscribed(應答建立),unsubscribed(應答取消)。
AB訂閱:
<presence from=‘a@longbourn.lit/outside’ to=‘b@pemberley.lit’ type=‘subscribe’/>
<presence from=‘b@pemberley.lit/library’ to=‘a@longbourn.lit/outside’ type=‘subscribed’/>
<presence from=‘b@pemberley.lit/library’ to=‘a@longbourn.lit’ type=‘subscribe’/>
<presence from=‘a@longbourn.lit/outside’ to=‘b@pemberley.lit/library’ type=‘subscribed’/>
(4)、定向出席
他是一種直接發給另一個用戶或其他某個實體的普通presence節。這里可以用來向那些沒有進行出席訂閱的實體傳送出席狀態信息。也就是臨時出席。
這里當發送者變成不可訪問的狀態的時候,出席信息的接收者將會自動得到通知,即使發送者忘記顯示的通知接收者。這里可以使用定向出席來臨時地掌握某個用戶的可訪問性。
2)、message
從一端到另一端發送消息。這個節屬于發出后不再過問,可靠性不能保證。一旦消息發出去了,發送者就不會知道他是不是傳送出去了,也不會知道到達的時間。
message示例:
單人聊天
<message from=‘a@netherfield.lit/frawing_room’ to=‘b@pemberley.lit’ type=‘chat’>
<body>adf</body>
</message>
多人聊天
benlent夫人向聊天室bennets@chat.merython.lit發送消息,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(不支持或者不方便應答的自動化服務使用)。
type是可以省略的,默認為normal,但是我們應該提供一個type值,
(2)、消息內容
<body>元素包含著該消息中人們的可讀的內容。只要有不同的xml:lang屬性就可以使用多個<body>。
<thread>元素用來創建線索,他的內容是一個用來區分不同線索的唯一標識符。應答節應該包含與所應答的節相同的<thread>元素。 (線索:向電子郵件一樣)
在消息中,可以使用XHTML-IM來給消息提供格式化,超鏈接,以及富媒體。也可以使用Chat State Notifications來允許用戶通告對方自己正在撰寫消息或有空。(qq的正在輸入)
3)、iq
這個節表示的時info/query(信息與查詢),他給xmpp童心提供請求和響應機制。和http的基本工作原理想死,允許獲取和設置查詢。(get 和 post)
每個節都需要有一個響應,但是這個節的必須的id將用來把響應與導致該響應的請求關聯起來。
type:get,set請求節; result,error為響應節。
下面看示例,每個iq節必須匹配id屬性
a向服務器發送了一個格式錯誤的花名冊請求
<iq from=a@longbourn.lit/garden’ type=‘get’ id=‘roster1’>
<query cmlns=‘jabber:iq:roster’/>
</iq>
<iq to=‘a@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>
重新發送
<iq from=a@longbourn.lit/garden’ type=‘get’ id=‘roster2’>
<query cmlns=‘jabber:iq:roster’/>
</iq>
<iq to=‘a@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添加到花名冊,回復空白iq來應答成功。
<iq from=‘a@longbourn.lit/garden’ type=‘set’ id=‘roster3’>
<query xmlns=‘jabber:iq:roster’>
<item jid=“b@pemberley.lit’ name=‘b’/>
</query>
</iq>
<iq to=‘a@longbourn.lit/garden’ type=‘result’ id=‘roster3’/>
4)、error
在錯誤提示節中,必須將type設置為error,并且需要攜帶一個<error>子元素。
在error中,他的type類型為:cancel(不應該重試),continue(警告信息),modify(發送的數據需要一些修改才可以被接受),auth(通知實體在以某種方式進行身份驗證之后重試),wait(報告server臨時遇到問題,稍后重發)。
在<error>中,必須包含一個錯誤條件作為他的子元素,也可以在<error>元素的子元素中指定應用程序的特定錯誤條件。還可以包含一個<text>元素來進一步指出有關該錯誤的詳細信息。
要注意的是每個錯誤條件元素都必須位于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’/> 給出了請缺德應用程序錯誤提示信息
<text xmlns=‘urn:ietf:params:xml:ns:xmpp-stanzas>dfs</text> 包含了問題描述
</error>
XMPP****尋址:
xmpp網絡有一個或多個地址jid, a@aaa.llit 組成:節點、域、資源(帶有資源的jid是完整jid,沒有資源的jid是裸jid),其中節點和資源是可選的,域是必選的。
其中域是服務器等的可解析dns名稱。只有域組成的jid是有效的地址,表示服務器的地址。
其中指向域的節將由服務器自身處理,并且可能被路由到其他的組件或者插件上。
在本地時我們通常會識別域中的一個特定的用戶,它位于@之前,本地部分還可以用來識別其他對象,多人聊天服務將每個聊天室顯示為一個jid,節點部分指向聊天室。
jid的資源部分會標識一個特定的客戶端xmpp鏈接,對于xmpp客戶端來說,每個鏈接均被指派一個資源,如 用 a@aaa.lit/study和a@aaa.lit/library 來尋址,其中資源部分也可以用來識別其他對象,在多人聊天時,jid的資源被用來識別聊天室中的一個特定的用戶。
客戶端處理裸jid的時候,服務器自己將處理發往客戶端裸jid的節。如:一條發往某個客戶端的裸jid的消息將被轉發到該用戶的一個或多個已連接資源,如果該用戶離線,那么就將該消息存儲以后傳送。但是發給完整jid的節通常會直接路由到該資源所在的客戶端連接。可以將裸jid視為尋址用戶的賬戶,而不是尋址該用戶的某個已連接的客戶端。
xmpp****連接:
連接,流的建立,身份驗證以及斷開連接。
1).連接
發送節前要建立xmpp流,在流存在之前要建立通往xmpp服務器的連接。
客戶端和服務器利用域名系統將服務器的域名解析成一個能夠連接的地址。電子郵件服務特別的使用郵件交換臺記錄來提供處理特定域郵件的服務器列表。這樣一個知名服務器地址就不用處理每一項服務請求了。電子郵件在dns中有特殊的對待。現在服務記錄srv可用來為任意服務提供類似的功能。
當xmpp客戶端或服務器連接到另一個xmpp服務器的時候,首先要在服務器域中查詢適當的srv記錄。查詢應答中可能包含多條srv記錄,這樣就可以在多臺服務器間建立負載均衡鏈接。
當沒有找到合適的srv記錄的時候,應用程序試著直接連接到給定域。大多數庫也可以顯式制定要連接的服務器。
2).流的建立
向服務器發送起始元素<stream:stream>,就可以打開xmpp流。服務器通過發送響應流的起始標記<stream:stream>進行響應。
服務器先發送<stream:features>元素,詳細列舉xmpp流中支持的所有功能。這些功能大多數與可用的加密和身份驗證選項有關。
客戶端發給服務器
<?xml version=’1.0′?>
<stream:stream xmlns=’jabber:client’
xmlns:straem=’http://ethrx.jabber.org/streams’
version=’1.0′
to=’pemberley.lit’>
服務器應答
<?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>
根據數據交換信息指導pemberley.org服務器支持TLS,流壓縮zlib等。
在兩臺服務器間建立xmpp流的過程相同,但是 jabber:client換成 jabber:server才可以。
3).身份驗證
xmpp可以進行tls傳輸層安全加密,并且大多數客戶端默認使用。服務器支持tls加密后,客戶端就會啟動tls鏈接,并將當前套接字升級為一個加密套接字。創建一對新的xmpp流。
xmpp身份驗證使用sasl 簡單身份驗證與安全層協議,并支持多種身份驗證機制。服務器通提供明文驗證和基于md5摘要的驗證,但是某些服務器還支持通過kerberos或特殊令牌來驗證。
完成身份驗證后,客戶端必選為該鏈接綁定一個資源并啟動一個會話。如果用戶正在線路上查看xmpp流量,就會看到<bind><session>元素被發送出去。(在<iq>中) 如果客戶端沒有提供綁定的資源,那么服務器將為其選定一個。
當兩臺服務器相互連接的時候,服務器交換并驗證tls證書,或者接受服務器使用某種回撥協議通過dns來驗證發送者身份。
4).連接斷開
當用戶結束xmpp會話的時候,他們終止會話并斷開連接。最有禮貌的終止會話的方式是:先發送無效出席信息,然后關閉<stream:stream>元素。
通過發送最后的無效出席信息,用戶的聯系人能夠得知該用戶離開的原因。
<presence type=’unavailable’/>
</stream:stream>
然后,服務器終止發往客戶端的流。