🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
rfc 6120 为ietf提出的替换原有xmpp/jabber 核心协议frc 3920 ### 概述 可扩展的消息和出席信息协议(XMPP)是一个可扩展标记语言[XML](http://wiki.jabbercn.org/RFC6120#XML "RFC6120")应用,让任何两个或多个网络实体之间进行结构化和可扩展的准实时信息交流. 本文定义了XMPP的核心协议方法: XML流的配置和解除, 通道加密, 验证, 错误处理, 以及消息通讯基础, 网络可用性 ("presence"), 和 请求-应答 交互. ### 历史 XMPP的基本语法和语义最开始是由Jabber开源社区开发的, 主要是在1999年. 2002年, 根据 [IMP‑REQS](http://wiki.jabbercn.org/RFC6120#IMP.E2.80.91REQS "RFC6120") ,XMPP工作组被允许基于Jabber协议开发一个适合IETF的即时消息和出席信息技术. 到了2004年10月, 发布了 [RFC3920](http://wiki.jabbercn.org/RFC3920 "RFC3920") 和 [RFC3921](http://wiki.jabbercn.org/RFC3921 "RFC3921") , 意味着那时候XMPP的主要定义完成了. 从2004年开始,互联网社区已经获得了广泛的XMPP实现和布署经验, 包括XMPP标准基金会(XSF)主持下开展的正式的互操作性测试. 本文全面整合了从软件开发者和XMPP服务提供者得到的反馈, 包含了一系列向后兼容的修改, 结果是, 本文反映了互联网社区对于XMPP1.0核心功能的初步共识, 因此废止了[RFC 3920](http://tools.ietf.org/html/rfc3920 "http://tools.ietf.org/html/rfc3920"). ### 功能汇总 这个不规范的章节提供了一个方便开发者的XMPP功能汇总; 接下来的其他章节则是XMPP的规范定义. XMPP的目标是允许两个(或多个)实体通过网络来交换相关的小件结构化数据(所谓"XML节"). XMPP典型地使用分布式的 客户端-服务器 体系结构来实现, 这里客户端需要连接到一个服务器以获得对网络的访问,从而被允许和其他实体(可能在其他服务器上)交换XML节. 一个客户端连接到一个服务器,交换XML节,以及结束连接,这样的流程如下: 1. 确定要连接的IP地址和端口号, 典型的做法是对一个合格的域名做出解析( [3.2](http://wiki.jabbercn.org/RFC6120#.E5.90.88.E6.A0.BC.E5.9F.9F.E5.90.8D.E7.9A.84.E8.A7.A3.E6.9E.90 "RFC6120") ) 1. 打开一个传输控制协议 [TCP](http://wiki.jabbercn.org/RFC6120#TCP "RFC6120") 连接 1. 通过TCP打开一个XML流 [4.2](http://wiki.jabbercn.org/RFC6120#.E6.89.93.E5.BC.80.E4.B8.80.E4.B8.AA.E6.B5.81 "RFC6120") 1. 握手最好使用传输层安全性 [TLS](http://wiki.jabbercn.org/RFC6120#TLS "RFC6120") 来进行通道加密( [5](http://wiki.jabbercn.org/RFC6120#STARTTLS.E6.8F.A1.E6.89.8B "RFC6120") ) 1. 使用简单验证和安全层 [SASL](http://wiki.jabbercn.org/RFC6120#SASL "RFC6120") 机制来验证 ( [6](http://wiki.jabbercn.org/RFC6120#SASL.E6.8F.A1.E6.89.8B "RFC6120") ) 1. 绑定一个资源到这个留上 ( [7](http://wiki.jabbercn.org/RFC6120#.E8.B5.84.E6.BA.90.E7.BB.91.E5.AE.9A "RFC6120") ) 1. 和其他网络上的实体交换不限数量的XML节( [8](http://wiki.jabbercn.org/RFC6120#XML.E8.8A.82 "RFC6120") ) 1. 关闭XML流 ( [4.4](http://wiki.jabbercn.org/RFC6120#.E5.85.B3.E9.97.AD.E4.B8.80.E4.B8.AA.E6.B5.81 "RFC6120") ) 1. 关闭TCP连接 在XMPP中, 一个服务器可以选择性地连接到另一个服务器以激活域间或服务器间的通讯. 这种情形下, 两个服务器需要在他们自身之间建立一个连接然后交换XML节; 这个过程所做的事情如下: 1. 确定要连接的IP地址和端口号, 典型的做法是对一个合格的域名做出解析( [3.2](http://wiki.jabbercn.org/RFC6120#.E5.90.88.E6.A0.BC.E5.9F.9F.E5.90.8D.E7.9A.84.E8.A7.A3.E6.9E.90 "RFC6120") ) 1. 打开一个TCP连接 1. 打开一个XML流 [4.2](http://wiki.jabbercn.org/RFC6120#.E6.89.93.E5.BC.80.E4.B8.80.E4.B8.AA.E6.B5.81 "RFC6120") 1. 握手最好使用TLS来进行通道加密( [5](http://wiki.jabbercn.org/RFC6120#STARTTLS.E6.8F.A1.E6.89.8B "RFC6120") ) 1. 使用简单验证和安全层 [SASL](http://wiki.jabbercn.org/RFC6120#SASL "RFC6120") 机制来验证 ( [6](http://wiki.jabbercn.org/RFC6120#SASL.E6.8F.A1.E6.89.8B "RFC6120") ) * 1. 交换不限数量的XML节,可以服务器之间直接交换,也可以代表每台服务器上的相关实体来交换,例如那些连到服务器上的客户端 ( [8](http://wiki.jabbercn.org/RFC6120#XML.E8.8A.82 "RFC6120") ) 1. 关闭XML流 ( [4.4](http://wiki.jabbercn.org/RFC6120#.E5.85.B3.E9.97.AD.E4.B8.80.E4.B8.AA.E6.B5.81 "RFC6120") ) 1. 关闭TCP连接 - 互操作性提示: 在本文写就的时候, 大多数已布署的服务器仍使用服务器回拨协议 [XEP‑0220](http://wiki.jabbercn.org/RFC6120#XEP.E2.80.910220 "RFC6120") 来提供弱身份验证,而不是使用SASL的 PKIX证书来提供强验证, 特别在这些情况下,SASL握手无论如何将不会得到强验证 (例如, 因为TLS握手没有被对方服务器强制要求, 或因为当TLS握手时对方服务器提供的PKIX证书是自签名的并且之前没有被接受过); 细节请见 [XEP‑0220](http://wiki.jabbercn.org/RFC6120#XEP.E2.80.910220 "RFC6120") . 本文的解决方案显然提供了一个更高级别的安全性 (参见 [13.6](http://wiki.jabbercn.org/RFC6120#.E9.AB.98.E5.AE.89.E5.85.A8.E6.80.A7 "RFC6120") ). 本文指定了客户端如何连接到服务器以及基本的XML节语义. 然而, 本文不定义一个连接成功建立之后可能用来交换的XML节的"载荷"; 反之, 那些载荷被定义在各种XMPP扩展之中. 例如, [XMPP‑IM](http://wiki.jabbercn.org/RFC6120#XMPP.E2.80.91IM "RFC6120") 定义了基本的即时消息和出席信息功能的扩展. 另外, XSF创造了各种扩展协议,即XEP系列 [XEP‑0001](http://wiki.jabbercn.org/RFC6120#XEP.E2.80.910001 "RFC6120") ,也为广泛的应用程序定义了扩展. ### 术语 本文中的关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 和 "OPTIONAL" 的解释参见[RFC 2119](http://tools.ietf.org/html/rfc2119 "http://tools.ietf.org/html/rfc2119") [关键字](http://wiki.jabbercn.org/RFC6120#.E5.85.B3.E9.94.AE.E5.AD.97 "RFC6120") . 特定的安全相关的术语的含义参见 [安全术语](http://wiki.jabbercn.org/RFC6120#.E5.AE.89.E5.85.A8.E6.9C.AF.E8.AF.AD "RFC6120") ; 这些术语包括但不限于, "assurance", "attack", "authentication", "authorization", "certificate", "certification authority", "certification path", "confidentiality", "credential", "downgrade", "encryption", "hash value", "identity", "integrity", "signature", "self-signed certificate", "sign", "spoof", "tamper", "trust", "trust anchor", "validate", and "verify". 特定的和证书,域名,应用服务身份相关的术语参见 [TLS‑证书](http://wiki.jabbercn.org/RFC6120#TLS.E2.80.91.E8.AF.81.E4.B9.A6 "RFC6120") ; 这包括但不限于, "PKIX certificate", "source domain", "derived domain", 以及身份类型 "CN-ID", "DNS-ID", 和 "SRV-ID". 其他安全相关的术语定义于参考协议中 (例如, "denial of service" (拒绝服务)定义于 [DOS](http://wiki.jabbercn.org/RFC6120#DOS "RFC6120") 或 "end entity certificate" (终端实体证书)定义于 [PKIX](http://wiki.jabbercn.org/RFC6120#PKIX "RFC6120") ). 术语 "whitespace" (空格) 用于指代 [XML](http://wiki.jabbercn.org/RFC6120#XML "RFC6120") 中任何匹配"S"的字符或字符串, 也就是说, 一个或多个满足 [ABNF](http://wiki.jabbercn.org/RFC6120#ABNF "RFC6120") 定义的SP, HTAB, CR, 或 LF 规则的实例. 术语 "localpart" (本地部分), "domainpart" (域部分), 以及 "resourcepart" (资源部分)定义于 [XMPP地址](http://wiki.jabbercn.org/RFC6120#XMPP.E5.9C.B0.E5.9D.80 "RFC6120") . 术语 "bare JID" (纯JID) 指代一个格式为 <localpart@domainpart> (对于一个位于某个服务器上的帐户而言) 或 <domainpart> (对于一个服务器而言) 的XMPP地址. 术语 "full JID" (全JID) 指代一个格式为 <localpart@domainpart/resourcepart> (对一个典型的已授权客户端或和某个帐号相关的设备而言) 或 <domainpart/resourcepart> (对于一个典型的资源或和某个服务器相关的文字)的XMPP地址. 术语 "XML stream" (也称为 "stream" (流)) 定义于 [4.1](http://wiki.jabbercn.org/RFC6120#.E6.B5.81.E7.9A.84.E5.9F.BA.E6.9C.AC.E5.8E.9F.E7.90.86 "RFC6120") . 术语 "XML stanza" (也称为 "stanza" (节)) 定义于 [4.1](http://wiki.jabbercn.org/RFC6120#.E6.B5.81.E7.9A.84.E5.9F.BA.E6.9C.AC.E5.8E.9F.E7.90.86 "RFC6120") . 有三种 stanzas(节): message, presence, 和 IQ ("Info/Query"的简称). 这些通讯原语分别定义于 [8.2.1](http://wiki.jabbercn.org/RFC6120#Message.E8.AF.AD.E4.B9.89 "RFC6120") , [8.2.2](http://wiki.jabbercn.org/RFC6120#Presence.E8.AF.AD.E4.B9.89 "RFC6120") , 和 [8.2.3](http://wiki.jabbercn.org/RFC6120#IQ.E8.AF.AD.E4.B9.89 "RFC6120") . 术语 "originating entity" (原实体)指的是第一次生成一个发送到XMPP网络的stanza(节)的实体(例如, 一个已连接的客户端, 一个附加的服务, 或一个服务器). 术语 "generated stanza" (生成的节)值的是生成的节那个节. 术语 "input stream" (输入流)指定这样一个XML流,服务器通过这个流从一个已连接的客户端或远端服务器接收数据, 而术语 "output stream" (输出流)指定这样一个流,服务器通过这个流发送数据到一个已连接的客户端或远程服务器. 以下术语指定一些动作,处理从输入流收到的数据时服务器可以执行这些动作: route(路由): 传递数据到一个远端服务器让它自行处理或最终递送到一个和远端服务器关联的客户端 deliver(递送): 传递数据到一个已连接的客户端 ignore(忽略): 丢弃数据不做任何处理或返回一个错误给发送者sender 当术语 "ignore" (忽略)用于客户端处理收到的数据时, 短语 "without acting upon it" (不做任何处理)明确的包括不展示任何数据给使用者(人). 接下来的 "XML符号" 被 [IRI](http://wiki.jabbercn.org/RFC6120#IRI "RFC6120") 用于展示无法用仅用ASCII码呈现的字符, 本文的一些例子使用了类似 "&#x...." 的格式来表现 [UNICODE](http://wiki.jabbercn.org/RFC6120#UNICODE "RFC6120") 字符串 (例如, 字符串 "ř" 表示Unicode字符 LATIN SMALL LETTER R WITH CARON); 这种形式是绝对不会在XMPP系统将通过网络发送的. 和 [URI](http://wiki.jabbercn.org/RFC6120#URI "RFC6120") 展现统一资源定位符的规则一样, XMPP地址文本也是用 '<' 和 '>' 括起来的(尽管基本上它们不属于 URIs). 例如, 被括起来的行是用来提高可读性的, "[...]" 表示省略, 并且还是用了以下预定义字符串 (这些预定义的字符串不会通过网络发送出去): - C: = 客户端 - E: = 任何XMPP实体 - I: = 发起实体 - P: = 对端服务器 - R: = 接收实体 - S: = 服务器 - S1: = 服务器1 - S2: = 服务器2 读者需要注意这些例子不包括细节, 并且例子里的一些协议流程中, 展示的备用步骤不一定是由前一个步骤发送的确切的数据触发的; 本文或常用参考文档中的协议规范所用到的所有用例里面提供的例子都遵从上述规则. 所有例子都是虚构的并且交换的信息 (例如, 用户名和密码) 不代表任何现存的用户和服务器. ### 体系结构 XMPP提供一种异步的端到端的结构化数据交换技术,在一个分布式的可全球寻址和出席信息感知的客户端和服务器的网络中使用直接的持久XML流。这种体系结构形式包含了普遍的网络可用性的知识,以及在给定的客户端-服务器和服务器-服务器会话的时候,不限数量的并发信息交易的概念,所以我们把它称为 "并发交易可用性" ("Availability for Concurrent Transactions") (简称ACT) 来把它和来自WWW的 "Representational State Transfer" [REST](http://wiki.jabbercn.org/RFC6120#REST "RFC6120") 体系结构形式区别开. 尽管XMPP的体系结构很大程度上类似于 email (参见 [EMAIL‑ARCH](http://wiki.jabbercn.org/RFC6120#EMAIL.E2.80.91ARCH "RFC6120"), 它引入了一些变化以便于准实时通讯. ACT体系结构形式的独特特性如下. ### 全局地址 和email一样, 为了通过网络路由和递送消息,XMPP使用全球唯一地址(基于DNS). 所有XMPP实体可以在网络上被寻址, 大部分客户端和服务器以及很多外部服务可以被客户端和服务器访问. 通常, 服务器地址的格式为 <域部分> (例如, <im.example.com>), 属于某台服务器的帐号的格式为 <本地部分@域部分> (例如, <juliet@im.example.com>, 称为 "纯JID"), 而连接到一个特定的设备或资源并且已经被(服务器)授权可以和外部交互的客户端的格式为 <本地部分@域部分/资源部分> (例如, <juliet@im.example.com/balcony>, 称为 "全JID"). 因为历史原因, XMPP地址常被称为Jabber IDs 或 JIDs. 因为XMPP地址格式的正式规范依赖于国际化技术(本文撰写时正在制定中),这个格式定义于 [XMPP‑ADDR](http://wiki.jabbercn.org/RFC6120#XMPP.E2.80.91ADDR "RFC6120") 而非本文之中. 术语 "localpart"(本地部分), "domainpart"(域部分), 和 "resourcepart"(资源部分) 正式定义于 [XMPP‑ADDR](http://wiki.jabbercn.org/RFC6120#XMPP.E2.80.91ADDR "RFC6120") . ### 出席信息 XMPP让一个实体能够向其他实体声明它的网络可用性或者 "presence"(出席信息) . 在XMPP中, 这种可通讯状态是用端到端的专用通讯元素来标识的: 即 <presence/> 节. 尽管网络可用性对于XMPP消息交换并不是必需的, 它还是可以促进实时交互,因为消息发起者可以在发消息之前知道接收者在线并处于可通讯状态. 端到端的出席信息定义于 [XMPP‑IM](http://wiki.jabbercn.org/RFC6120#XMPP.E2.80.91IM "RFC6120") . ### 持久流 每个点对点的一"跳"都建立了基于TCP长连接的持久XML流来保持可通讯状态. 这些 "always-on" 客户端-服务器 和 服务器-服务器 流使得任何时间每方都能够推送数据到另一方并且立即路由和递送. XML流定义于 [4](http://wiki.jabbercn.org/RFC6120#XML.E6.B5.81 "RFC6120") . ### 结构化数据 XMPP中基本的协议数据单元不是一个XML流 (它只是为点对点通讯提供传输层) 而是一个 XML 节("stanza"), 它是一个通过流发送的XML片段. 一个节的根元素包括路由属性 (类似 "from" 和 "to" 地址), 而节的子元素包含了递送给目标接收者的载荷. XML节定义于 [8](http://wiki.jabbercn.org/RFC6120#XML.E8.8A.82 "RFC6120") . ### 客户端和服务器的分布式网络 在实践之中, XMPP是一个包含了很多互相通讯的客户端和服务器的网络(当然, 任何两个给定的布署服务器之间的通讯都是严格谨慎的并且也和本地服务策略有关). 因此, 例如, 与服务器 <im.example.com> 关联的用户 <juliet@im.example.com> 能够和服务器 <example.net> 关联的用户 <romeo@example.net> 交换消息,出席信息和其他结构化数据. 这个模式对使用全局地址的消息协议是很常见的, 例如email网络 (见 [SMTP](http://wiki.jabbercn.org/RFC6120#SMTP "RFC6120") 和 [EMAIL‑ARCH](http://wiki.jabbercn.org/RFC6120#EMAIL.E2.80.91ARCH "RFC6120") . 结果, 在XMPP中端到端的通讯是逻辑上的点对点,而物理结构则是 客户端-服务器-服务器-客户端, 如下图所示. **图1: 分布式客户端-服务器 体系结构** ~~~ example.net <--------------> im.example.com ^ ^ | | v v romeo@example.net juliet@im.example.com ~~~