MUC
房间属性设置
以上属性存储在MUCPersistenceManager
private staticConcurrentHashMap<String,MUCServiceProperties> propertyMaps =newConcurrentHashMap<String,MUCServiceProperties>();
创建房间
客户端创建房间案例
第一:客户端发出查询请求
-
<iq id="wcCqI-57" to="[email protected]" type="get">
-
<query xmlns="http://jabber.org/protocol/disco#info"/>
-
</iq>
服务器将数据包发送到托管在该服务器组件来处理。
routed = routeToComponent(jid,packet, routed);
服务器需要在内存中判断房间是否存在,其次呢,返回外部组件的配置。为确切请求子域的查询将会作出修改。如果没有被发现和使用通配符请求,然后再查询将被提出,在使用通配符这个时候。
然后检查组件是否被托管在此JVM
获取MUC组件的信息
该MUC服务将接收的域MUC的域相匹配的所有数据包服务。这意味着,例如,disco 请求应该由服务本身作出回应,而不是依赖在服务器上处理请求。
根据命名空间找到相应处理——>IQDiscoInfoHandler。
http://jabber.org/protocol/disco#info
寻找与所请求的实体相关的DiscoInfoProvider。
我们认为该数据包为单位的接收者的JID的主机。这是DiscoInfoProvider责任提供有关的JID的姓名信息一起用任何可能的请求节点。
所查询的房间节点不存在,按照正常的流程服务器返回错误信息
-
<iq type="error" id="wcCqI-57" from="[email protected]" to="[email protected]/Spark 2.6.3#android">
-
<query xmlns="http://jabber.org/protocol/disco#info"/>
-
<error code="404" type="cancel">
-
<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
-
</error>
-
</iq>
客户端第二轮发送:
-
<presence id="wcCqI-59" to="[email protected]/test2">
-
<x xmlns="http://jabber.org/protocol/muc"/>
-
</presence>
服务器处理:
1.将用户发送的定向存在的实体
(通知方式发送到该处理程序,当用户发送了一个指向存在的实体。如果存在的发件人是本地的(这个服务器)和目标实体不属于用户的花名册,然后发送更新派驻执导的用户注册表。)
2.广播到所有连接的资源
(获得由XMPPAddress聊天的用户。仅返回已连接到该JVM的用户。)
服务器返回消息:
-
<message type="groupchat" from="[email protected]">
-
<body>确认配置之前已锁住该房间,禁止进入。</body>
-
</message>
配置钱锁定房间,一面别的用创建一样的,或者申请加入这个房间
-
<presence id="wcCqI-59" to="[email protected]/Spark 2.6.3#android"
-
from="[email protected]/test2">
-
<x xmlns="http://jabber.org/protocol/muc#user">
-
<item jid="[email protected]/Spark 2.6.3#android"
-
affiliation="owner" role="moderator"/>
-
<status code="201"/>
-
</x>
-
</presence>
客户端发送IQ:
-
<iq id="wcCqI-60" to="[email protected]" type="get">
-
<query xmlns="http://jabber.org/protocol/muc#owner"/>
-
</iq>
查询房间拥有者。
服务器返回1:
服务器返回2:
-
<iq type="error" id="wcCqI-60" from="[email protected]"
-
to="[email protected]/Spark 2.6.3#android">
-
<query xmlns="http://jabber.org/protocol/muc#owner"/>
-
<error code="401" type="auth">
-
<not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
-
</error>
-
</iq>
======================================================================
总的对话
客户端发送C2S - RECV (32671720):
-
<iq id="wcCqI-61" to="[email protected]" type="get">
-
<query xmlns="http://jabber.org/protocol/disco#info">
-
</query>
-
</iq>
服务器返回
-
<iq type="error" id="wcCqI-61"
-
from="[email protected]"
-
to="[email protected]/Spark 2.6.3#android">
-
<query xmlns="http://jabber.org/protocol/disco#info"/>
-
<error code="404" type="cancel">
-
<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
-
</error>
-
</iq>
以上循环两次对话,这可能由于debug超时原因,消息重复发送。
客户端发送
-
<presence id="wcCqI-63" to="[email protected]/test2">
-
<x xmlns="http://jabber.org/protocol/muc">
-
</x>
-
</presence>
出席消息。
服务器处理:
1.当用户发送一个 directed presence的时候将发送给directedPresenceSent()来处理。如果存在的发件人是本地的(这个服务器)和目标实体不属于用户的花名册,然后发送更新派驻执导的用户注册表。
跟踪所有指示派驻人员名册,如果服务被禁用
这里有两块内存记录消息:
private Cache<String,Collection<DirectedPresence>>directedPresencesCache;
跟踪发送指向派驻到其他实体。
在这个Cache上我们跟踪每一个 directed presence存在,无论发送者是否托管在这个JVM或其他群集节点。
另一个
private Map<String,Collection<DirectedPresence>>localDirectedPresences;
发送相同directedPresencesCache但只有不断派驻指导
用户连接到该JVM。
在方法directedPresenceSent()中主要对两个变量开始操作,这里有一个开锁和解锁的过程。
updateHandler.directedPresenceSent(packet, jid, recipientJID.toString());
2.路由消息包
被发送到XMPP域的组件路由数据包(这是XMPP域的子域)
首先检查组件是否被托管在此JVM
存在,交由component.processPacket(packet);出数据包
该MUC服务将接收的域MUC服务的域相匹配的所有数据包。
这意味着,例如,disco请求应该由服务本身作出回应,而不是依赖在服务器上处理请求。
在getChatRoom()方法中会从数据库中加载了房间的配置(如果房间是持久性的,但被添加到数据库服务器启动或房间可能是旧的房间,这是不存在于记忆体后)
这里OF服务器检查到房间需要重新创建的情况下,它没有预先创建(或已被删除不知何故,预计委托存在)。
因为房间不存在,所以接下来就该检测拥有者的创建权限了。依次添加room到内存中,以免其他创建者冲突。
开始创建房间事件——>通知其他集群节点,一个新的空间可用.
检查客户端创建密码或客户端对MUC的支持
(注:获取房间组件的基本信息
Long serviceID = XMPPServer.getInstance().getMultiUserChatManager().
getMultiUserChatServiceID(room.getMUCService().getServiceName());)
服务器返回1:
-
<presence id="wcCqI-63" to="[email protected]/Spark 2.6.3#android"
-
from="[email protected]/test2">
-
<x xmlns="http://jabber.org/protocol/muc#user">
-
<item jid="[email protected]/Spark 2.6.3#android"
-
affiliation="owner" role="moderator"/>
-
<status code="201"/>
-
</x>
-
</presence>
给自己发送出席
服务器返回2:
客户端发送:
-
<iq id="wcCqI-64" to="[email protected]" type="get">
-
<query xmlns="http://jabber.org/protocol/muc#owner">
-
</query>
-
</iq >
根据namespace服务器将有IQOwnerHandler来处理
refreshConfigurationFormValues()房间配置信息
服务器返回:
客户端发送1
-
<iq id="wcCqI-65" to="[email protected]" type="set">
-
<query xmlns="http://jabber.org/protocol/muc#owner">
-
<x xmlns="jabber:x:data" type="submit">
-
<field var="FORM_TYPE" type="hidden">
-
<value>http://jabber.org/protocol/muc#roomconfig</value>
-
</field>
-
<field var="muc#roomconfig_roomname" type="text-single">
-
<value>room2</value>
-
</field>
-
<field var="muc#roomconfig_roomdesc" type="text-single">
-
<value>测试2</value>
-
</field>
-
<field var="muc#roomconfig_roomowners" type="jid-multi">
-
<value>[email protected]</value>
-
</field>
-
</x>
-
</query>
-
</iq>
在这一步操作,是客户端来设置房间的一些配置信息,并且保存到DB(在类LoaclMUCRomm.saveToDB()方法中)
然后保存用户(普通用户,管理员).
服务端返回1
服务端返回2
客户端发送
-
<iq id="wcCqI-66" to="[email protected]" type="get">
-
<query xmlns="http://jabber.org/protocol/disco#info">
-
</query>
-
</iq>
处理类:IQDiscoInfoHandler
服务端返回
-
<iq type="result" id="wcCqI-66" from="[email protected]"
-
to="[email protected]/Spark 2.6.3#android">
-
<query xmlns="http://jabber.org/protocol/disco#info">
-
<identity category="conference" name="room2" type="text"/>
-
<feature var="http://jabber.org/protocol/muc"/>
-
<feature var="muc_public"/><feature var="muc_membersonly"/>
-
<feature var="muc_moderated"/>
-
<feature var="muc_nonanonymous"/>
-
<feature var="muc_unsecured"/>
-
<feature var="muc_persistent"/>
-
<feature var="http://jabber.org/protocol/disco#info"/>
-
<x xmlns="jabber:x:data" type="result">
-
<field var="FORM_TYPE" type="hidden">
-
<value>http://jabber.org/protocol/muc#roominfo</value>
-
</field>
-
<field var="muc#roominfo_description" label="描述">
-
<value>测试2</value>
-
</field>
-
<field var="muc#roominfo_subject" label="主题">
-
<value></value>
-
</field>
-
<field var="muc#roominfo_occupants" label="占有者人数">
-
<value>1</value>
-
</field>
-
<field var="x-muc#roominfo_creationdate" label="创建日期">
-
<value>20131202T02:22:08</value>
-
</field>
-
</x>
-
</query>
-
</iq>
加入房间
客户端加入房间,首先获取房间信息
-
<iq id="BfI3V-47" to="[email protected]" type="get">
-
<query xmlns="http://jabber.org/protocol/disco#info"/>
-
</iq>
服务端通过查找服务器组件获取房间信息并返回如下报文
-
<iq type="result" id="BfI3V-55" from="[email protected]" to="[email protected]/Spark 2.6.3#android">
-
<query xmlns="http://jabber.org/protocol/disco#info">
-
<identity category="conference" name="room2" type="text"/>
-
<feature var="http://jabber.org/protocol/muc"/>
-
<feature var="muc_public"/>
-
<feature var="muc_open"/>
-
<feature var="muc_unmoderated"/>
-
<feature var="muc_nonanonymous"/>
-
<feature var="muc_unsecured"/>
-
<feature var="muc_persistent"/>
-
<feature var="http://jabber.org/protocol/disco#info"/>
-
<x xmlns="jabber:x:data" type="result">
-
<field var="FORM_TYPE" type="hidden">
-
<value>http://jabber.org/protocol/muc#roominfo</value>
-
</field>
-
<field var="muc#roominfo_description" label="描述">
-
<value>测试房间2</value>
-
</field>
-
<field var="muc#roominfo_subject" label="主题">
-
<value></value>
-
</field>
-
<field var="muc#roominfo_occupants" label="占有者人数">
-
<value>0</value>
-
</field>
-
<field var="x-muc#roominfo_creationdate" label="创建日期">
-
<value>20131202T07:08:32</value>
-
</field>
-
</x>
-
</query>
-
</iq>
客户端再次发送状态
-
<presence id="BfI3V-57" to="[email protected]/test2"><x xmlns="http://jabber.org/protocol/muc"></x></presence>
服务端返回:
-
<presence id="BfI3V-57" to="[email protected]/Spark 2.6.3#android" from="[email protected]/test2"><x xmlns="http://jabber.org/protocol/muc#user"><item jid="[email protected]/Spark 2.6.3#android" affiliation="owner" role="moderator"/></x></presence>
-
<message type="groupchat" from="[email protected]" to="[email protected]/Spark 2.6.3#android"><body>该房间不是匿名的。</body><x xmlns="http://jabber.org/protocol/muc#user"><status code="100"/></x></message>
邀请用户
请求用户发送消息内容
-
<message id="BfI3V-64" to="[email protected]">
-
<x xmlns="http://jabber.org/protocol/muc#user">
-
<invite to="[email protected]">
-
<reason>请把我加入会议中。</reason>
-
</invite>
-
</x>
-
</message>
组件将消息发送给客户端test1,如图:
Test1接收邀请
发送消息:
-
<presence id="6808K-48" to="[email protected]/test1">
-
<x xmlns="http://jabber.org/protocol/muc"/>
-
</presence>
服务端将发送如下消息
OK,关于会议室这块就到次结束。这里读起来很难理解很正常。基于xmpp协议的通讯消息太繁琐了。但是只要读者细心debug调试,还是不难的。
我在上面中的jid,如:jid="[email protected]/Spark 2.6.3#android,这里面有个#号。而实际上在openfire正常的通讯是没的
这是本人调试测试多加了个jid属性。关于jid部分,本人会单独拿出来写博文的。欢迎阅读,不对之处请联系本人指正