手机客户端需要实现即时通信功能,在通信协议上采用开放的Jabber(XMPP)协议,整个XMPP协议最为核心也是最为复杂的部分是Subscription的运行机制,抓取了一下相关的通信协议报文,供开发时候参考。
1. 测试环境
1.1. 测试软件环境:
Jabber服务器:Openfire 3.5.2
Jabber客户端:Spark 2.5.8
抓包:Wireshark
1.2. 服务器环境:
Jabber服务器:192.168.1.12,安装Openfire,域为home1
Jabber用户客户端:192.168.1.10,安装Spark客户端,Jabber用户为chuanliang。
Jabber联系人客户端:192.168.1.11,安装Spark客户端,Jabber用户为liangchuan
1.3. 测试场景:
测试1:
Jabber用户chuanliang和Jabber联系人liangchuan被彼此的presence订阅,且允许把彼此加入自己的Roster
测试2
Jabber联系人liangchuan接受Jabber用户chuanliang的订阅,但是不允许chuanliang加入自己的Roster
测试3
Jabber联系人liangchuan不接受Jabber用户chuanliang的订阅,同时不允许chuanliang加入自己的Roster
以测试用例“测试1”说明一下测试过程:
1、 [email protected]在192.168.1.10客户端上新增联系人[email protected]
2、 [email protected]在192.168.1.11客户端上“准许[email protected]新增[email protected]到chuanlian的联系人名单中”,同时”Add user to liangchuan’s roster”
3、 [email protected]在192.168.1.10客户端上“准许[email protected]新增[email protected]到chuanlian的联系人名单中”,同时”Add user to chuanliang’s roster”
2. 测试1- contact accept subscription and allow add user to it’s roster
2.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端
Ø 192.168.1.10->192.168.1.12
Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster
<iq id="7SJ55-63" type="set">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.10
Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:
<iq type="set" id="308-51" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan" subscription="none">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.10
Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。
<iq type="result" id="7SJ55-63" to="[email protected]/spark"/>
2.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端
Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)
Ø 192.168.1.10->192.168.1.12
<presence id="7SJ55-64" to="[email protected]" type="subscribe"/>
Ø 192.168.1.12->192.168.1.10
Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:
<iq type="set" id="132-52" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan" ask="subscribe" subscription="none">
<group>Friends</group>
</item>
</query>
</iq>
2.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端
Ø 192.168.1.12->192.168.1.11
Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端
<presence id="7SJ55-64" to="[email protected]" type="subscribe" from="[email protected]"/>
Ø 192.168.1.11->192.168.1.12
Jabber联系人客户端发送一个<iq/>包给Jabber服务器,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster:
<iq id="8SAVC-26" type="set">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="chuanliang">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.11
Jabber联系人客户端从服务器接收到一个<iq/>包,其type=’result’
<iq type="result" id="8SAVC-26" to="[email protected]/spark"/>
2.4. Jabber联系人客户端发送一个type=’subscribe’的<presence/>的包给用户客户端
此部分请求发生在联系人客户端“准许[email protected]新增[email protected]到chuanlian的联系人名单中”时候同时选择了:“Add user to liangchuan’s roster”选项。如果没有选择,则无此部分请求。
Ø 192.168.1.11->192.168.1.12
<presence id="8SAVC-27" to="[email protected]" type="subscribe"/>
Ø 192.168.1.12->192.168.1.10
服务器传递请求给Jabber用户端
<presence id="8SAVC-27" to="[email protected]" type="subscribe" from="[email protected]"/>
Ø 192.168.1.12->192.168.1.10
<iq type="set" id="867-55" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name
="liangchuan" subscription="to">
<group>Friends</group>
</item>
</query>
</iq>
2.5. Jabber联系人客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给用户客户端
联系人下一步要做的就是决定是否接受订阅请求。我们假定联系人接受订阅请求
Ø 192.168.1.11->192.168.1.12
联系人的Jabber客户端发送一个type=’subscribed’的<presence/>的包给Jabber用户(通过服务器端)
<presence id="8SAVC-28" to="[email protected]" type="subscribed"/>
Ø 192.168.1.12->192.168.1.10
<presence id="8SAVC-28" to="[email protected]" type="subscribed" from="[email protected]"/>
<presence id="8SAVC-6" from="liangc[email protected]/spark" to="[email protected]/spark">
<status/>
<priority>1</priority>
</presence>
Ø 192.168.1.12->192.168.1.11
联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”
<iq type="set" id="14-54" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="chuanliang" ask="subscribe" subscription="from">
<group>Friends</group>
</item>
</query>
</iq>
2.6. Jabber用户客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给联系人客户端
Ø 192.168.1.10->192.168.1.12
<presence id="7SJ55-65" to="[email protected]" type="subscribed"/>
Ø 192.168.1.12->192.168.1.10
<iq type="set" id="382-56" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan" subscription="both">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.11
<iq type="set" id="697-57" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="chuanliang" subscription="both">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.11
<presence id="7SJ55-65" to="[email protected]" type="subscribed" from="[email protected]"/>
<presence id="7SJ55-51" from="chuanl[email protected]/spark" to="[email protected]/spark">
<status/>
<priority>1</priority>
</presence>
3. 测试2- contact accept subscribption and not allow add user to it’s roster
3.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端
Ø 192.168.1.10->192.168.1.12
Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster
<iq id="xHk99-51" type="set">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.10
Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:
<iq type="set" id="133-130" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan" subscription="none">
<group>Friends</group>
</item>
</query>
</iq>
Ø 192.168.1.12->192.168.1.10
Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。
<iq type="result" id="xHk99-51" to="[email protected]/spark"/>
3.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端
Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)
Ø 192.168.1.10->192.168.1.12
<presence id="xHk99-52" to="liangc[email protected]" type="subscribe"></presence>
Ø 192.168.1.12->192.168.1.10
Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:
<iq type="set" id="35-132" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" name="liangchuan" ask="subscribe" subscription="none">
<group>Friends</group>
</item>
</query>
</iq>
3.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端
Ø 192.168.1.12->192.168.1.11
Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端
<presence id="xHk99-52" to="[email protected]" type="subscribe" from="[email protected]"/>
3.4. Jabber联系人客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给用户客户端
联系人下一步要做的就是决定是否接受订阅请求。我们这里联系人接受订阅请求,但是取消”Add user to chuanliang’s roster”操作。
Ø 192.168.1.11->192.168.1.12
联系人的Jabber客户端发送一个type=’subscribed’的<presence/>的包给Jabber用户(通过服务器端)
<presence id="8SAVC-90" to="chuanli[email protected]" type="subscribed"></presence>
Ø 192.168.1.12->192.168.1.10
<presence id="8SAVC-90" to="[email protected]" type="subscribed" from="[email protected]"/>
<presence id="8SAVC-30" from="liangc[email protected]/spark" to="[email protected]/spark">
<status/>
<priority>1</priority>
</presence>
Ø 192.168.1.12->192.168.1.11
联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”
<iq type="set" id="585-135" to="[email protected]/spark">
<query xmlns="jabber:iq:roster">
<item jid="[email protected]" subscription="from"/>
</query>
</iq>
4. 测试3- contact not accept subscription and not allow add user to it’s roster
4.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端
转载请注明:出家如初,成佛有余 » Jabber协议分析之Subscriptions运行机制-Presence subscription