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>
然后,服务器终止发往客户端的流。