基于xmpp的协议即时通讯软件开发–理论(一)

我在大二下学期的时候接触安卓,当时学完基础之后一直想做一个软件。想做的东西有很多,但唯独对即时通讯这块非常感兴趣,我很好奇微信背后实现的原理是什么。一番周折,我接触到了xmpp协议。如今闲暇,遂提笔记录当初开发学习之路。前几部分比较枯燥,主要讲解xmpp协议内容,后面会进入实战部分

xmpp起源非常之久(我那时候估计还在上幼稚园): 基本语法语义最初是由 Jabber 开源 区在 1999 年开 发的。2002 年,XMPP 工作组授权开发一个 Jabber 协议的改写本,将适用于 IETF 的即时消息(IM)与出席技术。

如今的xmpp大多是以客户-服务器架构设计的,客户端通过一个xmpp基于tcp与服务器进行连接,而服务器之间也可以通过tcp进行通信。其中服务器呢,有一下几个职能:

1) 管理连接其它实体的会话,以 XML 流格式(第 4 节)在已授权的客户端、服务器以及其它实体间来回传送。
2) 通过 XML 流在实体间路由具有合适地址的 XML 节。大多数与 XMPP 兼容的服务器设想有能力存储客户端的数据(例:基于 XMPP即时消息与出席应用的用户的联系列表);在这种情况下,XML 数据由服务器自身代表客户端直接处理,并不路由到其它实体。

xmpp的寻址:

处于历史原因,这个被称作jid.

jid= [ node “@” ] domain [ “/” resource ]
domain = fqdn / address-literal
fqdn = (sub-domain 1*(“.” sub-domain))
sub-domain= (internationalized domain label)
address-literal = IPv4address / IPv6address

所以标识一个即时消息用户、用户连接的服务器、用户连接的资源(例如:特别的客户端)的形式就为:

<[url=mailto:user@host/resource]user@host /resource[/url]>

但这个是最简单的例子,如果我们想实现更复杂的功能比如聊天室:一个提供多用户聊天服务的特别聊天室,可以以< [url=mailto:room@service]room@service[/url]>(“room”是聊天室名,“service”是多用 户聊天服务的主机名)作为地址。并且,此聊天室的特别拥有者可能以< [url=mailto:room@service/nick]room@service/nick[/url]>(“nick”是此拥有者的房间 昵称)作地址,许多其它 JID 类型均有可能(例如:<domain/resource>可能是一个服务器端脚本或服务)。

使 presence–‐aware 实体间能够相互迅速的、异步交换相关的小负载的结构化信息有两种
基本元素:XML 流与 XML 节。

XML 流定义:

XML 流是一个容器,用于 络上任意两实体间交换 XML 元素。XML 流的开始是以一个起始的 XML<stream>标记(有合        适的属性与命名空间声明)表示,XML 流的结尾以一个结束的 XML</stream>标记表示。在流的生命周期中,初始化它的实体能够通过流发送极多的 XML 元素,元素与 XML 节(定义在此,<message/>,       <presence/>,        或        <iq/>元素由缺省命名空间验证)都用于协商流(例:协商使用 TLS或使用 SASL。“初始流”是从初始实体(通常是一个客户端或服务器)到接收实体(通常是一个服务器)的协商,并被看作与从初始实体到接收实体的会话一致。初始流能从初始实体到接收实体单向通信;为了能够从接收实体到初始实体的信息交换,接收实体必须在反方向协商一个流(“响应流”)。      

XML 节定义:

XML 节是一个不连续的结构化信息语义单元,通过 XML 流从一个实体发送到另一个实体。XML 节以根</stream>的直接子层存在,如果它匹配产品内容[XML],则可以很好的平衡。任何 XML 节的开始都由深度为 1 的 XML 流(例如:<presence>)的开始标记元素来清楚的表示, XML 节的结尾由相应的深度为 1 的关闭标记来清楚的表示。为传送想要的信息,一个 XML 节可能包含必要的子元素(带有属性,元素,XML 字符数据)。在此定义的仅有的XML 节是<message/>,<presence/>,<iq/>元素,由流的缺省命名空间验证,在 XML 节 中描述;为传输层安全(TLS:Transport  Layer  Security)协商,SASL 协商,或服务器回叫而发送的 XML 元素,并不会当作 XML 节来考虑。

考虑一个客户端与服务器的会话例子。为了连接到服务器,客户端必须初始化一个 XML流:发送一个起始的<stream>标记给服务,可选先于一个指定 XML 版本的文本声明与字符编码支持(参考文本声明的内容;也可参考字符编码)。服从本地策略与所提供的服务,服务器接下来应该回复另一个 XML 流给客户端,再次可选先于一个文本声明。一但客户端完成了 SASL 协商,客户端可以通过流发送极多的 XML 节给 络上的任意容器。当客户端想关闭流时,它简单发送一个关闭</stream>标记给服务器(也可以由服务器来关闭流),从这以后,客户端与服务器都应终止潜在的连接(通常是一个 TCP 连接)。        
       
习惯于将 XML 考虑成以文档为中心的人可能希望看到客户端与服务器的会话作为两个末端开口的(自由回答的)XML 文档的组成部分:一个从客户端到服务器, 另一个从服务器到客户端。从这个观点看,根<stream/>元素可被认为是每个“文档”的文档实体,两个“文档”都由通过两个 XML 流发送的 XML 节的集聚来建立。然而,这种观点仅是一种方便; XMPP
并不以文档处理,而是以 XML 流或 XML 节来处理。  本质上,那么,一个 XML 流充当了所有通过会话发送的 XML 节的信封。可用图简

流错误       
           根流元素可能包含一个<error/>子元素,此元素由流命名空间前缀来加前缀。如果错误子元素感觉到一个流级别错误发生,它必须由一个兼容实体(通常是一个服务器而不是一个客户端)来发送。     

规则       
          以下规则应用于流级别错误:       
           1)        设想所有流级别错误均是不可恢复的;因此,如果一个错误在流级别层发生,那么检测错误的实体必须发送一个流错误给其它实体,发送一个关闭</stream>标记,并终止潜在的 TCP 连接。       
           2)         如果在流被建立期间发生错误,接收实体必须一直发送起始<stream>标记,将<error/>元素作为流元素的子元素,发送 关闭</stream>标记,并终止潜在的 TCP 连接。此种情况下,如果初始实体在‘to’属性(或根本没提供‘to’属性)中提供了一个未知主机,服务器应当在流头的‘from’属性中提供服务器的授权主机名,并在终止前发送。     

语法       
            流错误语法如下:       
                 

<error/>元素:       
                         1)        必须包含一个子元素,此子元素与以下定义的已定义的节错误条件之一相一致;此元素必须被’urn:ietf:params:xml:ns:xmpp–‐streams’命名空间认为是合的。   
                         2)        可能包含一个<text/>子元素,此子元素包含了更详细描述错误的 XML 字符数据;此元素必须被’urn:ietf:params:xml:ns:xmpp–‐streams’命名空间认为是合格的,并且,应当拥有一个’xml:lang’属性来指明XML 字符数据的自然语言。       
                         3)        可能包含一个用于说明特殊应用错误条件的子元素;此元素必须由一个已定义应用命名空间来认证,并且,它的结构由那个命名空间来定义。      

<text/>元素是:

                         它可选的。如果包含了此元素,它应当仅用于提供描述性或诊断性的信息,来补充一个已定义的条件或特殊应用条件的意思;它不应当由一个应用以程序化的形式叙
述。它不应当作为错误消息展示给一个用户,但可能另外显示与包含条件元素(或元素们)相关的错误消息。     

已定义条件       
                        以下定义了流级别错误条件:       
                                1) <bad–‐format/>–‐–‐已经发送 XML 的实体不能被处理;此错误可能用于代替更特殊的 XML相关错误,例如:<bad–‐namespace–‐prefix/>,<invalid–‐xml/>,       
<restricted–‐xml/>, <unsupported–‐encoding/>,<xml–‐not–‐well–‐formed/>,虽然更特殊的错误是首选。       
                                2)<bad–‐namespace–‐prefix/>–‐–‐实体已经发送了一个不被支持的名空间前缀,或在一个需要那样一个前缀的元素中发送了没有命名空间的前缀(参考 XML 命名空间名与前缀(11.2))。        
                                3)<conflict/>–‐–‐服务器正为实体关闭活动流,因为一个已经被初始化的新流与现存流冲突。       
                                4)<connection–‐timeout/>–‐–‐一段时间内(可根据本地服务策略配置)实体并不通过流产生任何通信。       
                                5)<host–‐gone/>–‐–‐由初始实体在流头中提供的‘to’属性值对应于一个主机名,而此主机名已不再被一个服务器当作主机了。       
                                6)<host–‐unknown/>–‐–‐由初始实体在流头中提供的‘to’属性值于服务器所拥有的主机名不一致。    

                                7)<improper–‐addressing/>–‐–‐一个在两个服务器间发送的节,缺少‘to’或‘from’属性(或此属性无值)       
                                8)<internal–‐server–‐error/>–‐–‐服务器经历了错误配置或其它未定义内部错误使其无法提供服务。      
                                9)<invalid–‐from/>–‐–‐在‘from’地址中提供的 JID 或主机名与已授权的 JID 或有效域协商不匹配,此有效域协商为通过 SASL 或回叫服务器间的协商,或通过授权与资源绑定的客户端与服务器间的协商。       
                               10)<invalid–‐id/>–‐–‐流 ID 或回叫 ID 是无效的或与以前提供的 ID 不匹配。       
                               11)<invalid–‐namespace/>–‐–‐流命名空间名不只是 http://etherx.jabber.org/streams,或回叫命名空间名不只是”jabber:server:dialback”(参考 XML 命名空间名与前缀)       
                               12) <invalid–‐xml/>–‐–‐实体通过流向执行验证的服务器发送了无效的 XML       
                               13)<not–‐authorized/>–‐–‐实体试图在流被认证前发送数据,或不授权执行一个相关流协商的活动;接收实体在发送流错误前不准处理违规节。       
                               14)<policy–‐violation/>–‐–‐实体违反了某些本地策略;服务器可能选择在<text/>元素或特殊–‐应用条件元素中指定策略。       
                               15)<remote–‐connection–‐failed/>服务器不能适当的连接到远程实体,需要认证或授权。        
                               16)<resource–‐constraint/>服务器缺少提供服务给流的必要的系统资源。       
                               17)<restricted–‐xml/>实体试图发送受限的 XML 特征,例如评注、处理介绍,DTD,实体参考,或保留字符(参考(11.1))。       
                               18) <see–‐other–‐host/>服务器将不提供服务给初始实体,但正重定向传输给另一个主机;服务器应当指定替换的主机名或 IP 地址(必须是有效域标识符),作为<see–‐other–‐host/>元素的 XML 字符数据。       
                               19)<system–‐shutdown/>服务器被关闭,并且所有的活动流被关闭。       
                               20)<undefined–‐condition/>错误条件是由此列表中的其它已定义条件中的一个;此错误条件应当仅用在与特殊–‐应用条件相结合。       
                               21)<unsupported–‐encoding/>初始实体已在不被服务器支持的编码中为流编码(11.5)       
                               22)<unsupported–‐stanza–‐type/>初始实体已发送了一个不被服务器支持的第一级子流。       
                               23) <unsupported–‐version/>由初始实体在流头提供的版本属性值指定了一个不被服务器支持的 XMPP 版本;服务器可能在<text/>元素中指定它支持的版本。     
                               24)<xml–‐not–‐well–‐formed/>初始实体已经发送了不标准的 XML,标准的 XML 由[XML]定义。

示例


范例:

此部分包含两个简化的客户端与服务器(“C”行是从客户端发送到服务器,而“S”行是由服务器发送到客户端)间基于流会话的例子;这些例子解释进一步的概念。


A “session” gone bad:

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2015年10月11日
下一篇 2015年10月11日

相关推荐