Tigase插件 – packets是如何被session manager和plugins处理的

本文翻译自 – http://www.tigase.org/content/how-packets-are-processed-sm-and-plugins
理解插件是如何工做的对开发插件是很是重要的,在不一样的场景下由不一样类型的插件来负责处理packet。在开始正式的编码工做以前,建议你现阅读一下下面的文档。 html

什么是IQ(储天行注:这一个部分是在翻译时额外添加的,原文中没有)

在开始以前,先介绍一下什么是IQ。这个东西出如今后面的不少地方。Google了一下,IQ的意思是Info/Query:它是一种请求和应答机制,和http有一些相似的地方。 IQ的语意容许一个实体向另外一个实体发送请求,并从另外一个实体获取应答。请求和应答当中的数据在IQ元素的第一级子节点(命名空间的声明)当中被定义,请求方实体能够经过id标签来跟踪交互过程。如此一来,IQ交互的数据交换模式就相似于“get/result” 或者 “set/result”(在某些状况下,也多是get/error和set/error)。若有困惑请参考XMPP官方英文文档:http://xmpp.org/rfcs/rfc3920.html#stanzas-semantics-iq 算法

Requesting                 Responding
  Entity                     Entity
----------                 ----------
    |                           |
    | <iq type='get' id='1'>    |
    | ------------------------> |
    |                           |
    | <iq type='result' id='1'> |
    | <------------------------ |
    |                           |
    | <iq type='set' id='2'>    |
    | ------------------------> |
    |                           |
    | <iq type='error' id='2'>  |
    | <------------------------ |
    |                           |

为了可以确保这种方式被执行,有以下规则须要遵照: 数据库

  1. 每个IQ stanza都必须含有“id”标签和值
  2. 每个IQ stanza都必须含有“type”标签和值,且值必须为以下的几种:
    • get — 是一个请求信息
    • set — 提供了所须要的数据,设置了新的值或者替换某些已经存在的值
    • result — 一个对应get或set而且执行成功的应答
    • error — 以前发送的一个get或set发生了处理或者传输错误
  3. 若是一个实体接收到了“set”或“get” IQ请求,那么它必须回复一个“result”或“error”应答,而且应答的id标签值必须与请求的id标签值保持一致。
  4. 若是一个实体接收到了“result”或“error” stanza,那么它必定不能再返回“result”或“error”应答;可是发出请求的实体能够能够继续发送下一个请求。
  5. 一个“get” 或 “set”类型的 IQ stanza必须包含并只包含一个子元素指明特定请求或应答的语义。
  6. 一个“result”类型的 IQ stanza必须包含零或一个子元素。
  7. 一个“error”类型的IQ stanza应该包含有两个子元素。第一个子元素包含着与之发生错误相对应的“get”或“set”,第二个子元素是<error/>元素。

plugin简介

插件是一段负责处理特定XMPP stanza的代码。有专门负责处理消息的插件,有专门负责处理在线状态的插件,有专门负责处理iq通信录的插件,也有专门负责处理版本的插件。 服务器

插件经过xmlns和元素名来声明全部它“感兴趣”的那些在特定命名空间下的特定XML元素名,因此你能够建立一个对那些包含caps元素的packet“感兴趣”的插件。 session

对于那些没有插件“感兴趣”的stanza元素,它们会被直接传递到消息的目标地址。相反的,也有一些特定的stanza可能会被多个插件“感兴趣”,在这种状况下,多个插件可能会被多个线程同时进行处理,因此没法确保哪一个插件先进行处理哪一个插件后进行处理。 wordpress

每个stanza都会被session manager一步一步得进行处理,看看下面的图: 编码

stanza在SM中的处理 spa

就像图片里面展现的那样,stanza在session manager里面分四步进行处理: 插件

  1. 预处理 – 全部已加载的预处理器都会接收stanza并进行处理。它们在session manager的内部线程里被调用,插件本身自己没有消息队列。须要注意的是:因为它们在session manager的内部线程中被调用,算法的执行效率会直接限制SM的执行最小时间(多多少少都会拖慢SM的执行速度)。设置预处理器的目的是为了阻止packet完成后续处理。若是预处理器返回的结果是true,那么这个packet就会被阻塞,被阻塞的packet再也不进行后续处理。
  2. 处理 – 若是packet没有被预处理器阻塞,那么它会进入这一步进行处理。它会被插入到那些对它的特定元素“感兴趣”的处理器队列中。每个处理器都拥有一个固定长度的处理队列,并在独立的线程里被调用。
  3. 投递处理 – 若是一个stanza没有被任何一个处理器处理,那么它就进入了这一步进行处理。内建的最后一个投递处理器会对它执行默认处理。一般默认处理是直接把这个packet发送到目的地地址。大多数状况这个packet是<message/>。
  4. 过滤 – 最后,若是上面的任何一个步骤产生了输出或result packet,那么这个输出或result packet会进入这一步进行处理,每个过滤器均可能产生“阻塞”或“容许经过”的结果。

须要提醒两点: 线程

  • 有两个地方或两种方法可以阻塞/过滤packet。一个地方是在“处理”前被“预处理”过程阻塞;另外一个在“处理”完毕后,处理结果被“过滤”。
  • session manager和处理器的执行方式像是一个packet消费者。packet先被处理,处理一旦结束,它就被销毁了。因此在把一个packet发送处处理器以前,必须对packet进行复制,设置好全部的属性而后把它做为结果输出。固然处理器也能够输出任意多个packet做为结果,上面四个步骤当中的任何一个步骤均可以产生结果packet。看看下图:

用户发送packet

若是packet p1要向服务器外部发送(好比要发送给另一台服务器的一个用户,或者另一个组件 – MUC/PubSub/transport之类的),那么服务器中的第一个处理器必须为p1建立一个备份p2,而且正确设置好全部的全部的属性和目的地地址。当p1被SM在处理过程当中销毁,最终服务器中的插件还可以产生一个新的packet。

若是是组件向用户发送也是同样:


组件向用户发送

在来自组件的packet被销毁以前,服务器中的一个插件必须作好备份,并最终把备份投递给用户。固然了投递操做在packet没有被任何插件处理时会做为默认行为被执行。

这样设计的缘由是:输入packet-p1会在SM中被多个插件在多个线程中同时处理,因此packet的值在处理过程当中必定不能被改变。

最明显的处理过程是当一个用户向服务器发送一个指令并但愿从服务器得到一个应答:

用户向服务器发送一个请求并获取应答

这种设计产生惊人的结果。若是你看完下面两个用户之间的交互,你会发现,packet在投递到目的地以前被拷贝了两次:



一个用户向另外一个用户发送packet

就像图片所展现的那样,packet被SM处理了两次。第一次是做为用户A的传出packet进行处理,第二次是做为用户B的传入packet进行处理。

这样作的目的是为了首先肯定用户A有权限发送packet,而后是肯定用户B有权限接收数据。若是用户B不在线,那么离线消息处理器会把packet保存到数据库当中。

相关文章
相关标签/搜索