转:http://blog.csdn.net/huwenfeng_2011/article/details/43413817

MUC

房间属性设置

以上属性存储在MUCPersistenceManager

private staticConcurrentHashMap<String,MUCServiceProperties> propertyMaps=newConcurrentHashMap<String,MUCServiceProperties>();

创建房间

客户端创建房间案例

第一:客户端发出查询请求

  1. <iq id="wcCqI-57" to="room1@qqgroup.8ntmorv1ep4wgcy" type="get">
  2. <query xmlns="http://jabber.org/protocol/disco#info"/>
  3. </iq>

服务器将数据包发送到托管在该服务器组件来处理。

routed = routeToComponent(jid,packet, routed);

服务器需要在内存中判断房间是否存在,其次呢,返回外部组件的配置。为确切请求子域的查询将会作出修改。如果没有被发现和使用通配符请求,然后再查询将被提出,在使用通配符这个时候。

然后检查组件是否被托管在此JVM

获取MUC组件的信息

该MUC服务将接收的域MUC的域相匹配的所有数据包服务。这意味着,例如,disco 请求应该由服务本身作出回应,而不是依赖在服务器上处理请求。

根据命名空间找到相应处理——>IQDiscoInfoHandler。

http://jabber.org/protocol/disco#info

寻找与所请求的实体相关的DiscoInfoProvider。
我们认为该数据包为单位的接收者的JID的主机。这是DiscoInfoProvider责任提供有关的JID的姓名信息一起用任何可能的请求节点。

所查询的房间节点不存在,按照正常的流程服务器返回错误信息

  1. <iq type="error" id="wcCqI-57" from="room1@qqgroup.8ntmorv1ep4wgcy" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <query xmlns="http://jabber.org/protocol/disco#info"/>
  3. <error code="404" type="cancel">
  4. <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
  5. </error>
  6. </iq>

客户端第二轮发送:

  1. <presence id="wcCqI-59" to="room1@qqgroup.8ntmorv1ep4wgcy/test2">
  2. <x xmlns="http://jabber.org/protocol/muc"/>
  3. </presence>

服务器处理:

1.将用户发送的定向存在的实体

(通知方式发送到该处理程序,当用户发送了一个指向存在的实体。如果存在的发件人是本地的(这个服务器)和目标实体不属于用户的花名册,然后发送更新派驻执导的用户注册表。)
2.广播到所有连接的资源

(获得由XMPPAddress聊天的用户。仅返回已连接到该JVM的用户。)

服务器返回消息:

  1. <message type="groupchat" from="room1@qqgroup.8ntmorv1ep4wgcy">
  2. <body>确认配置之前已锁住该房间,禁止进入。</body>
  3. </message>

配置钱锁定房间,一面别的用创建一样的,或者申请加入这个房间

  1. <presence id="wcCqI-59" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"
  2. from="room1@qqgroup.8ntmorv1ep4wgcy/test2">
  3. <x xmlns="http://jabber.org/protocol/muc#user">
  4. <item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"
  5. affiliation="owner" role="moderator"/>
  6. <status code="201"/>
  7. </x>
  8. </presence>

客户端发送IQ:

  1. <iq id="wcCqI-60" to="room1@qqgroup.8ntmorv1ep4wgcy" type="get">
  2. <query xmlns="http://jabber.org/protocol/muc#owner"/>
  3. </iq>

查询房间拥有者。

服务器返回1:

  1. <message type="groupchat" from="room1@qqgroup.8ntmorv1ep4wgcy" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <body>确认配置之前已锁住该房间,禁止进入。</body>
  3. </message>

服务器返回2:

  1. <iq type="error" id="wcCqI-60" from="room1@qqgroup.8ntmorv1ep4wgcy"
  2. to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  3. <query xmlns="http://jabber.org/protocol/muc#owner"/>
  4. <error code="401" type="auth">
  5. <not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
  6. </error>
  7. </iq>

======================================================================

总的对话

客户端发送C2S - RECV (32671720):

  1. <iq id="wcCqI-61" to="room2@qqgroup.8ntmorv1ep4wgcy" type="get">
  2. <query xmlns="http://jabber.org/protocol/disco#info">
  3. </query>
  4. </iq>

服务器返回

  1. <iq type="error" id="wcCqI-61"
  2. from="room2@qqgroup.8ntmorv1ep4wgcy"
  3. to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  4. <query xmlns="http://jabber.org/protocol/disco#info"/>
  5. <error code="404" type="cancel">
  6. <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
  7. </error>
  8. </iq>

以上循环两次对话,这可能由于debug超时原因,消息重复发送。

客户端发送

  1. <presence id="wcCqI-63" to="room2@qqgroup.8ntmorv1ep4wgcy/test2">
  2. <x xmlns="http://jabber.org/protocol/muc">
  3. </x>
  4. </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:

  1. <presence id="wcCqI-63" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"
  2. from="room2@qqgroup.8ntmorv1ep4wgcy/test2">
  3. <x xmlns="http://jabber.org/protocol/muc#user">
  4. <item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"
  5. affiliation="owner" role="moderator"/>
  6. <status code="201"/>
  7. </x>
  8. </presence>

给自己发送出席

服务器返回2:

  1. <message type="groupchat"    from="room2@qqgroup.8ntmorv1ep4wgcy"
  2. to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  3. <body>确认配置之前已锁住该房间,禁止进入。</body>
  4. </message>

客户端发送:

  1. <iq id="wcCqI-64" to="room2@qqgroup.8ntmorv1ep4wgcy" type="get">
  2. <query xmlns="http://jabber.org/protocol/muc#owner">
  3. </query>
  4. </iq >

根据namespace服务器将有IQOwnerHandler来处理

refreshConfigurationFormValues()房间配置信息

服务器返回:

  1. <iq type="result" id="wcCqI-64" from="room2@qqgroup.8ntmorv1ep4wgcy"       to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <query xmlns="http://jabber.org/protocol/muc#owner">
  3. <x xmlns="jabber:x:data" type="form">
  4. <title>房间配置</title>
  5. <instructions>
  6. 已创建房间“room2”。要接受缺省配置,请单击“确定”按钮。
  7. 或填写以下表单以完成设置:
  8. </instructions>
  9. <field var="FORM_TYPE" type="hidden">
  10. <value>http://jabber.org/protocol/muc#roomconfig</value>
  11. </field>
  12. <field var="muc#roomconfig_roomname" type="text-single"
  13. label="房间名称">
  14. <value>room2</value>
  15. </field>
  16. <field var="muc#roomconfig_roomdesc" type="text-single"
  17. label="描述">
  18. <value>room2</value>
  19. </field>
  20. <field var="muc#roomconfig_changesubject" type="boolean"
  21. label="允许占有者更改主题">
  22. <value>1</value>
  23. </field>
  24. <field var="muc#roomconfig_maxusers" type="list-single"
  25. label="最大房间占有者人数">
  26. <option label="10">
  27. <value>10</value>
  28. </option>
  29. <option label="20">
  30. <value>20</value>
  31. </option>
  32. <option label="30">
  33. <value>30</value>
  34. </option>
  35. <option label="40">
  36. <value>40</value>
  37. </option>
  38. <option label="50">
  39. <value>50</value>
  40. </option>
  41. <option label="无">
  42. <value>0</value>
  43. </option>
  44. <value>30</value>
  45. </field>
  46. <field var="muc#roomconfig_presencebroadcast" type="list-multi"
  47. label="其 Presence 是 Broadcast 的角色">
  48. <option label="主持者">
  49. <value>moderator</value>
  50. </option>
  51. <option label="参与者">
  52. <value>participant</value>
  53. </option>
  54. <option label="访客">
  55. <value>visitor</value>
  56. </option>
  57. <value>moderator</value>
  58. <value>participant</value>
  59. <value>visitor</value>
  60. </field>
  61. <field var="muc#roomconfig_publicroom" type="boolean"
  62. label="列出目录中的房间">
  63. <value>1</value>
  64. </field>
  65. <field var="muc#roomconfig_persistentroom" type="boolean"
  66. label="房间是持久的">
  67. <value>1</value></field>
  68. <field var="muc#roomconfig_moderatedroom" type="boolean"
  69. label="房间是适度的">
  70. <value>1</value>
  71. </field>
  72. <field var="muc#roomconfig_membersonly" type="boolean"
  73. label="房间仅对成员开放">
  74. <value>1</value>
  75. </field>
  76. <field type="fixed">
  77. <value>注意:缺省情况下,只有管理员才可以在仅用于邀请的房间中发送邀请。</value>
  78. </field>
  79. <field var="muc#roomconfig_allowinvites" type="boolean"
  80. label="允许占有者邀请其他人">
  81. <value>1</value>
  82. </field>
  83. <field var="muc#roomconfig_passwordprotectedroom" type="boolean"
  84. label="需要密码才能进入房间">
  85. <value>0</value>
  86. </field>
  87. <field type="fixed">
  88. <value>如果需要密码才能进入房间,则您必须在下面指定密码。</value>
  89. </field>
  90. <field var="muc#roomconfig_roomsecret" type="text-private"
  91. label="密码"/>
  92. <field var="muc#roomconfig_whois" type="list-single"
  93. label="能够发现占有者真实 JID 的角色">
  94. <option label="主持者">
  95. <value>moderators</value>
  96. </option>
  97. <option label="任何人">
  98. <value>anyone</value>
  99. </option>
  100. <value>anyone</value>
  101. </field>
  102. <field var="muc#roomconfig_enablelogging" type="boolean"
  103. label="登录房间对话">
  104. <value>1</value>
  105. </field>
  106. <field var="x-muc#roomconfig_reservednick" type="boolean"
  107. label="仅允许注册的昵称登录">
  108. <value>1</value>
  109. </field>
  110. <field var="x-muc#roomconfig_canchangenick" type="boolean"
  111. label="允许使用者修改昵称">
  112. <value>1</value>
  113. </field>
  114. <field type="fixed">
  115. <value>允许用户注册房间</value>
  116. </field>
  117. <field var="x-muc#roomconfig_registration" type="boolean"
  118. label="允许用户注册房间">
  119. <value>1</value>
  120. </field>
  121. <field type="fixed">
  122. <value>您可以指定该房间的管理员。请在每行提供一个 JID。</value>
  123. </field>
  124. <field var="muc#roomconfig_roomadmins" type="jid-multi"
  125. label="房间管理员"/>
  126. <field type="fixed">
  127. <value>您可以指定该房间的其他拥有者。请在每行提供一个 JID。</value>
  128. </field>
  129. <field var="muc#roomconfig_roomowners" type="jid-multi"
  130. label="房间拥有者">
  131. <value>test2@8ntmorv1ep4wgcy</value>
  132. </field>
  133. </x>
  134. </query>
  135. </iq>

客户端发送1

  1. <iq id="wcCqI-65" to="room2@qqgroup.8ntmorv1ep4wgcy" type="set">
  2. <query xmlns="http://jabber.org/protocol/muc#owner">
  3. <x xmlns="jabber:x:data" type="submit">
  4. <field var="FORM_TYPE" type="hidden">
  5. <value>http://jabber.org/protocol/muc#roomconfig</value>
  6. </field>
  7. <field var="muc#roomconfig_roomname" type="text-single">
  8. <value>room2</value>
  9. </field>
  10. <field var="muc#roomconfig_roomdesc" type="text-single">
  11. <value>测试2</value>
  12. </field>
  13. <field var="muc#roomconfig_roomowners" type="jid-multi">
  14. <value>test2@8ntmorv1ep4wgcy</value>
  15. </field>
  16. </x>
  17. </query>
  18. </iq>

在这一步操作,是客户端来设置房间的一些配置信息,并且保存到DB(在类LoaclMUCRomm.saveToDB()方法中)

然后保存用户(普通用户,管理员).

服务端返回1

  1. <message type="groupchat" from="room2@qqgroup.8ntmorv1ep4wgcy" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <body>该房间现在已解锁。
  3. </body>
  4. </message>

服务端返回2

  1. <iq type="result" id="wcCqI-65" from="room2@qqgroup.8ntmorv1ep4wgcy" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"/>

客户端发送

  1. <iq id="wcCqI-66" to="room2@qqgroup.8ntmorv1ep4wgcy" type="get">
  2. <query xmlns="http://jabber.org/protocol/disco#info">
  3. </query>
  4. </iq>

处理类:IQDiscoInfoHandler

服务端返回

  1. <iq type="result" id="wcCqI-66" from="room2@qqgroup.8ntmorv1ep4wgcy"
  2. to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  3. <query xmlns="http://jabber.org/protocol/disco#info">
  4. <identity category="conference" name="room2" type="text"/>
  5. <feature var="http://jabber.org/protocol/muc"/>
  6. <feature var="muc_public"/><feature var="muc_membersonly"/>
  7. <feature var="muc_moderated"/>
  8. <feature var="muc_nonanonymous"/>
  9. <feature var="muc_unsecured"/>
  10. <feature var="muc_persistent"/>
  11. <feature var="http://jabber.org/protocol/disco#info"/>
  12. <x xmlns="jabber:x:data" type="result">
  13. <field var="FORM_TYPE" type="hidden">
  14. <value>http://jabber.org/protocol/muc#roominfo</value>
  15. </field>
  16. <field var="muc#roominfo_description" label="描述">
  17. <value>测试2</value>
  18. </field>
  19. <field var="muc#roominfo_subject" label="主题">
  20. <value></value>
  21. </field>
  22. <field var="muc#roominfo_occupants" label="占有者人数">
  23. <value>1</value>
  24. </field>
  25. <field var="x-muc#roominfo_creationdate" label="创建日期">
  26. <value>20131202T02:22:08</value>
  27. </field>
  28. </x>
  29. </query>
  30. </iq>

加入房间

客户端加入房间,首先获取房间信息

  1. <iq id="BfI3V-47" to="room2@conference.8ntmorv1ep4wgcy" type="get">
  2. <query xmlns="http://jabber.org/protocol/disco#info"/>
  3. </iq>

服务端通过查找服务器组件获取房间信息并返回如下报文

  1. <iq type="result" id="BfI3V-55" from="room2@conference.8ntmorv1ep4wgcy" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <query xmlns="http://jabber.org/protocol/disco#info">
  3. <identity category="conference" name="room2" type="text"/>
  4. <feature var="http://jabber.org/protocol/muc"/>
  5. <feature var="muc_public"/>
  6. <feature var="muc_open"/>
  7. <feature var="muc_unmoderated"/>
  8. <feature var="muc_nonanonymous"/>
  9. <feature var="muc_unsecured"/>
  10. <feature var="muc_persistent"/>
  11. <feature var="http://jabber.org/protocol/disco#info"/>
  12. <x xmlns="jabber:x:data" type="result">
  13. <field var="FORM_TYPE" type="hidden">
  14. <value>http://jabber.org/protocol/muc#roominfo</value>
  15. </field>
  16. <field var="muc#roominfo_description" label="描述">
  17. <value>测试房间2</value>
  18. </field>
  19. <field var="muc#roominfo_subject" label="主题">
  20. <value></value>
  21. </field>
  22. <field var="muc#roominfo_occupants" label="占有者人数">
  23. <value>0</value>
  24. </field>
  25. <field var="x-muc#roominfo_creationdate" label="创建日期">
  26. <value>20131202T07:08:32</value>
  27. </field>
  28. </x>
  29. </query>
  30. </iq>

客户端再次发送状态

  1. <presence id="BfI3V-57" to="room2@conference.8ntmorv1ep4wgcy/test2"><x xmlns="http://jabber.org/protocol/muc"></x></presence>

服务端返回:

  1. <presence id="BfI3V-57" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" from="room2@conference.8ntmorv1ep4wgcy/test2"><x xmlns="http://jabber.org/protocol/muc#user"><item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" affiliation="owner" role="moderator"/></x></presence>
  2. <message type="groupchat" from="room2@conference.8ntmorv1ep4wgcy" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"><body>该房间不是匿名的。</body><x xmlns="http://jabber.org/protocol/muc#user"><status code="100"/></x></message>

邀请用户

请求用户发送消息内容

  1. <message id="BfI3V-64" to="room2@conference.8ntmorv1ep4wgcy">
  2. <x xmlns="http://jabber.org/protocol/muc#user">
  3. <invite to="test1@8ntmorv1ep4wgcy">
  4. <reason>请把我加入会议中。</reason>
  5. </invite>
  6. </x>
  7. </message>

组件将消息发送给客户端test1,如图:

Test1接收邀请

发送消息:

  1. <presence id="6808K-48" to="room2@conference.8ntmorv1ep4wgcy/test1">
  2. <x xmlns="http://jabber.org/protocol/muc"/>
  3. </presence>

服务端将发送如下消息

  1. <presence id="6808K-48" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" from="room2@conference.8ntmorv1ep4wgcy/test1">
  2. <x xmlns="http://jabber.org/protocol/muc#user">
  3. <item jid="test1@8ntmorv1ep4wgcy/Spark 2.6.3#android" affiliation="none" role="participant"/>
  4. </x>
  5. </presence>
  6. <presence id="BfI3V-57" to="test1@8ntmorv1ep4wgcy/Spark 2.6.3#android" from="room2@conference.8ntmorv1ep4wgcy/test2">
  7. <x xmlns="http://jabber.org/protocol/muc#user">
  8. <item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" affiliation="owner" role="moderator"/>
  9. </x>
  10. </presence>

OK,关于会议室这块就到次结束。这里读起来很难理解很正常。基于xmpp协议的通讯消息太繁琐了。但是只要读者细心debug调试,还是不难的。

我在上面中的jid,如:jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#Android,这里面有个#号。而实际上在openfire正常的通讯是没的

这是本人调试测试多加了个jid属性。关于jid部分,本人会单独拿出来写博文的。欢迎阅读,不对之处请联系本人指正。本人邮箱:

624308915@qq.com

最新文章

  1. Android动画学习(二)——Tween Animation
  2. MIME协议生成邮件
  3. iOS APP上线流程
  4. 关于Python中的yield
  5. AspNet MVC : 操作/控制器过滤器(action filter)
  6. Lucene 高亮功能
  7. ios 第三方qq授权登陆,第一次登陆后,再次登陆,失效
  8. java web从零单排第十七期《struts2》数据标签库(1)
  9. Scala Apply
  10. WebService第二天
  11. WinRAR5.31 注册码
  12. vmware虚拟机安装CentOS-6.5教程
  13. 网络1711班 C语言第八次作业批改总结
  14. UIImagePickerController照片选取器
  15. PAT甲级1049 Counting Ones【规律】
  16. 主机性能监控之wmi 获取进程信息
  17. linux下安装cmake(安装opencv库)
  18. Word2Vec实现原理(Hierarchical Softmax)
  19. mysql 触发器介绍
  20. JSP 获取真实IP地址的代码

热门文章

  1. vue开发环境及vue相关
  2. TP model where条件丢失
  3. 76 学习C++
  4. CDN技术之--集群服务与负载均衡
  5. ZROI week6
  6. wrtnode板
  7. 机器学习算法--Elastic Net
  8. 用 Flask 来写个轻博客 (16) — MV(C)_Flask Blueprint 蓝图
  9. Ngrinder简单使用
  10. expand gcc case variable length