XML流
概览
- 两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:
- XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).
- XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。
- 设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。
- 那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。
- 基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:
|--------------------| | <stream> | |--------------------| | <presence> | | <show/> | | </presence> | |--------------------| | <message to='foo'> | | <body/> | | </message> | |--------------------| | <iq to='bar'> | | <query/> | | </iq> | |--------------------| | ... | |--------------------| | </stream> | |--------------------|
绑定到TCP
- 虽然有很多非必需的连接使用XML流来绑定[TCP]连接(两个实体可以通过别的机制来互联,比如通过[HTTP]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。
流的安全
- 在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。
stream 属性
- stream 元素的属性如下:
-
- to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。
-
- from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。
-
- id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。
-
- xml:lang -- 'xml:lang'属性(定义在[XML]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在[XML]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 [LANGTAGS] 规定的格式。
-
- version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。
- 我们现在可以总结如下:
初始化方发给接收方 | 接收方发给初始化方 | |
---|---|---|
to | 接收方的主机名 | 忽略 |
from | 忽略 | 接收方的主机名 |
id | 忽略 | 会话键值 |
xml:lang | 缺省语言 | 缺省语言 |
version | 支持XMPP 1.0 | 支持XMPP 1.0 |
版本支持
- 在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.
- 如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。
- 以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:
- 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").
- 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.
- 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。
- 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.
名字空间声明
- 流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 [XML-NAMES]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀。如下:
XML 名字空间的名字和前缀
- XML名字空间[XML-NAMES]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.
流名字空间
- 在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.
缺省名字空间
- 在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).
- 一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):
-
- jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间
-
- jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间
- 一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.
- 如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.
- 注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义。如下:
消息语义学
- <message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).
出席信息语义学
- <presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或复用(multiplex)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.
IQ语义学
- 信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似[HTTP].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):
- 以下是IQ的流程图,参见附件iq.png
{image:img=iq}
请求实体 响应实体 ---------- ---------- | | | <iq type='get' id='1'> | | ------------------------> | | | | <iq type='result' id='1'> | | <------------------------ | | | | <iq type='set' id='2'> | | ------------------------> | | | | <iq type='error' id='2'> | | <------------------------ | | |
- 为了强制执行这些语义学,要应用以下规则:
- 1. 对于IQ节来说'id'属性是必需的(REQUIRED).
- 2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:
-
- get -- 这个节是一个对信息或需求的请求.
- set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.
- result -- 这个节是一个对一个成功的 get 或 set 请求的应答.
- error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).
-
- 3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).
- 4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).
- 5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.
- 6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.
- 7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (http://blog.csdn.net/love254443233/article/details/7887279).
回拨名字空间
- 所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.
流的特性
- 如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 XMPP-IM 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.
流错误
- 流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。
规则
- 以下规则适用于流级别的错误:
-
- 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。
-
- 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.
语法
- 流错误的语法如下:
<stream:error> <defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> <text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'> OPTIONAL descriptive text </text> [OPTIONAL application-specific condition element] </stream:error>
- <error/>元素:
- 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.
-
- 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。
-
- 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。
- <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。
已定义的条件
- 以下流级别的错误条件是已定义的:
-
- <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。
-
- <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).
-
- <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。
-
- <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).
-
- <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供
-
- <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.
-
- <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).
-
- <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.
-
- <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。
-
- <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.
-
- <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).
-
- <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).
-
- <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。
-
- <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。
-
- <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。
-
- <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。
-
- <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).
-
- <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。
-
- <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。
-
- <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.
-
- <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).
-
- <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.
-
- <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.
-
- <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).
应用程序定义条件
- 大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:
<stream:error> <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> <text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'> Some special application diagnostic information! </text> <escape-your-data xmlns='application-ns'/> </stream:error> </stream:stream>
简化的流示例
- 这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.
- 一个基本的 "会话":
C: <?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> S: <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> ... encryption, authentication, and resource binding ... C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'> C: <body>Art thou not Romeo, and a Montague?</body> C: </message> S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'> S: <body>Neither, fair saint, if either thee dislike.</body> S: </message> C: </stream:stream> S: </stream:stream>
- 一个不成功的 "会话" :
C: <?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> S: <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> ... encryption, authentication, and resource binding ... C: <message xml:lang='en'> <body>Bad XML, no closing body tag! </message> S: <stream:error> <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> </stream:error> S: </stream:stream>