OpenFire学习:XMPP协议

2019-06-04  本文已影响0人  机智小当家

一、概述

XMPP全称为可扩展通讯和表示协议,是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性。 因此,基于XMPP的应用具有超强的可扩展性。
优势:

二、基本网络结构

XMPP中定义了三个角色,客户端,服务器,网关。通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录,连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。基本的网络形式是单客户端通过TCP/IP)连接到单服务器,然后在之上传输XML。

示例-客户端:

<?xmlversion='1.0'?>
<stream:stream
  to='example_com'
    xmlns='jabber:client'
    xmlns:stream='http_etherx_jabber_org/streams'
version='1.0'>
    <messagefrom='juliet_example_com'
to='romeo_example_net'
xml:lang='zh-cn'>
        <body>你好,可以交个朋友吗?</body>
    </message>
</stream:stream>

示例-服务端:

<?xmlversion='1.0'?>
<stream:stream
  from='example_com'
  id='someid'
    xmlns='jabber:client'
    xmlns:stream='http_etherx_jabber_org/streams'
version='1.0'>
    <message from='romeo_example_net'
to='juliet_example_com'
xml:lang='zh-cn'>
        <body>当然可以</body>
    </message>
</stream:stream>

三、XML使用和说明

XMPP的协议,首先以<stream></stream>标签作为根节点,流的生命周期:标签的开头即是流的开始,标签的关闭即是流的结束。
在stream标签中,数据通过其内部的子标签(message、presence、iq等)当做数据实体,通过子标签可以定义大量的数据。

基本节点

1. presence

presence节点本身表示通知服务器自己的状态,用来控制和表示实体的在线状态,包含:离线(away)、在线()、离开、不能打扰等复杂状态,另外,还能白用来创建和结束在线状态的监听/订阅;
参考文档

在节点中,type字段是可选,为空则表示只是通知服务器自己在线。如果不为空, 则表示自己不在线的原因

  • Presence.Type.unavailable- signals that the entity is no longer available for communication.
  • Presence.Type.subscribe -- the sender wishes to subscribe to the recipient's presence.
  • Presence.Type.subscribed -- the sender has allowed the recipient to receive their presence.
  • Presence.Type.unsubscribe -- the sender is unsubscribing from another entity's presence.
  • Presence.Type.unsubcribed -- the subscription request has been denied or a previously-granted subscription has been cancelled.
  • Presence.Type.probe -- a request for an entity's current presence; SHOULD be generated only by a server on behalf of a user.
  • Presence.Type.error-- an error has occurred regarding processing or delivery of a previously-sent presence stanza.

1.1.子属性

Show

用于指定实体或特定资源的特定可用性状态,在presence中只能存在一个。数据值只能是以下之一:

<presence>
      <show>away</show> <!--离线-->
</presence>

1.2. Status

针对可用性的描述,通常和Show元素一起使用(例如:在会议中)。

<presence>
      <show>away</show> <!--离线-->
      <status>atthe ball</status> <!--标签用于显示额外信息-->
</presence>

1.3. Priority

用于指定资源的优先级。值在-128到127之间。

2. message

讲限定消息推送到聊天对话或多用户聊天室的消息实体。

2.1 主要属性

属性 说明
from 发送信息自身的Full ID。
to 设置信息接收方的Bare JID,通常在第一次发送方无法得知接收方的Full JID,通过服务器中转路由根据Base JID映射接收方的Full JID,尽量在to属性中包含对方的完成Full JID,减少服务器的接入定位。
id 该属性仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中必须是唯一的。注意:这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的。它不应该在有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该忽略它。
xml:lang 用于实现国际化的属性,表示发送的XML字符所使用的语言。
version 代表当前XML实体的版本
type 聊天类型

JID的结构:在XMPP网络上,每一个实体都有一个JID标识,JID是一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。如:jid = [ node "@" ] domain [ "/" resource ]

  • node:是对用户的抽象,既可以代表一个真实的用户,也能表示一个虚拟用户如一个聊天室等。
  • domain:表达了客户所连接的服务器,在实践中通常表示一个特定的集群,由同一domain来表示。
  • resource:它通常表示一个特定的会话,连接。对于服务器和和其他客户端来说,资源名是不透明的。

2.2 type

聊天类型:

2.3 子标签

2.3.1 subject

表示一个消息体的主题内容,通常在聊天窗口标题处。除了xml:lang之外,不会有其他属性。该元素可以有多个(每个lang不能重复,只能存在一个),方便不同语言不通的主题 。

<message
    to='romeo@example.net'
    from='juliet@example.com/balcony'
    type='chat'
    xml:lang='en'>
  <subject>I implore you!</subject>
  <subject
      xml:lang='cz'>&#x00DA;p&#x011B;nliv&#x011B; prosim!</subject>
  <body>Wherefore art thou, Romeo?</body>
  <body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body>
</message>
2.3.2 body

指定消息的文本内容。除了xml:lang之外,不会有其他属性。该元素可以有多个(每个lang不能重复,只能存在一个),方便不同语言不通的显示 。

<message
    to='romeo@example.net'
    from='juliet@example.com/balcony'
    type='chat'
    xml:lang='en'>
  <body>Wherefore art thou, Romeo?</body>
  <body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body>
</message>
2.3.3 thread

用于跟踪一个会话,该元素主要用于客户端实现消息展示(例如:消息历史查询时,每次会话折叠显示消息),每次会话会产生一个唯一的thread.id,xmpp推荐采用uuid算法。不同时间段的聊天内容,可能是基于多个会话,在查询聊天记录的时候,可以根据会话ID进行折叠显示。

<message
    to='juliet@example.com/balcony'
    from='romeo@example.net/orchard'
    type='chat'
    xml:lang='en'>
  <body>Neither, fair saint, if either thee dislike.</body>
  <thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread>
</message>

2.3.4 delay

表示该消失是一个离线消息。 <delay>子元素的from记录了延迟消息的最后来源方,如上例中from为capulet.com指接收离线消息人连接的服务器,离线消息最终由该服务器发出
stamp属性记录了离线消息的存储时间,客户端实现应显示该时间而非接收到的时间。

<message from='romeo@montague.net/orchard' to='juliet@capulet.com'>
  <body>
    收到,请回复信息。
  </body>
  <delay xmlns='urn:xmpp:delay'
     from='capulet.com' 
     stamp='2002-09-10T23:08:25Z'>Offline Storage</delay>
</message>

3. IQ

iq节点主要是用于Info/Query模式的消息请求,类似于HTTP的get/post请求,可以发出get以及set请求,期望有返回值(有result,error两种回应)。

type属性值:

  • Get: 获取当前域值
  • Set: 设置替换get查询的值
  • Result: 说明成功相应了先前的查询
  • Error: 查询或相应时候出现了错误
<iq to='example.com'
    type='set'
    id='sess_1'>
  <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
</iq>
image.png

4. 通信流程

使用Stream元素,用来表示客户端-服务器-客户端的通信建立,在建立通信时,需要保证以下两点:

<stream:stream
    xmlns='jabber:client'
    xmlns:stream='http://etherx.jabber.org/streams'
    id='c2s_345'
    from='example.com'
    version='1.0'>
<stream:features>
  <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
  <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
</stream:features>
<iq to='example.com'
    type='set'
    id='sess_1'>
  <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
  <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>  
    <resource>pc-win-someone</resource>  
  </bind>  
</iq>
<iq from='example.com'
    type='result'
    id='sess_1'>
  <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>  
     <jid>somenode@example.com/pc-win-someone-server-gen-random-string</jid>  
   </bind>  
</iq>

在会话创建有几种错误可能:

资源绑定:

  1. 标识客户端的平台
  2. 服务器为每个客户端生成随机值,生成唯一后缀,用于区分不同的客户端连接
  3. 相同账户的多点登录(多个终端登录),通过resource区分同一用户的不同接入点,方便策略的执行

完整数据流

1: 客户端初始化流给服务器:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>

2: 服务器发送一个流标签给客户端作为应答:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'>

3: 服务端发送TLS流特征说明(包括验证机制和任何其他流特性):
   <stream:features>
     <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>
       <required/>
     </starttls>
     <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
       <mechanism>DIGEST-MD5</mechanism>
       <mechanism>PLAIN</mechanism>
     </mechanisms>
   </stream:features>

4: 客户端发送 TLS握手给服务器:
   <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

5: 服务器通知客户端可以继续进行:
   <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
  (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
   </stream:stream>

6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手. resume是否允许恢复会话
   <enabled xmlns='urn:xmpp:sm:3' id='some-long-sm-id' resume='true'/>

7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
  (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.

8: 服务器发送一个加密流初始化给客户端,其中包括任何可用的流特性:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'>
8.1:服务端发送SASL特征说明,mechanism支出了服务支持的认证机制,有关SASL认证机制[RFC4422]
   <stream:features>
     <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
       <mechanism>DIGEST-MD5</mechanism>
       <mechanism>PLAIN</mechanism>
       <mechanism>EXTERNAL</mechanism>
     </mechanisms>
   </stream:features>

9: 客户端继续 SASL 握手
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth>  

5. 多用户文本聊天协议(Multi User Chat)

XMPP在其XEP-0045扩展中定义了一个用于多用户文本会议(群聊)的协议,类似于聊天室、QQ群等。由于它作为一个标准协议在定义模型上力求完备,涵盖了现实中的绝大部分IM产品模型,而现实中的IM产品基本都只实现了XMPP定义的模型中的一个子集。
XMPP定义的一些基本概念:

XMPP MUC协议扩展定义了一个广泛的用例集合,下面提取一些典型的核心场景来简要分析说明并辅助实现。

  1. MUC服务发现
    主要用于客户端向服务器咨询是否支持MUC,协议交互细节详见:MUC Discovering
  2. 新建房间
    从房间创建的视角来看,本质上有2种类型的房间:
    instant room 临时房间(类似于临时会话),适用于那些临时选取多个用户进行会话的场景
    reserverd room 永久房间(类似于固定群)
  3. 销毁房间
    销毁房间通常仅限于房间的所有者,临时房间通常是在房间所有用户都离开后自动销毁
  4. 加入房间
    加入房间可以有2种方式,申请和邀请
  5. 发言
    在房间内发言方式从使用场景的角度看通常有3种:
  1. 退出房间
    主动退出、管理员(主持人)踢出房间

6. 扩展协议

扩展协议

参考文档:

中文翻译
说明文档-英文版
安全验证

上一篇 下一篇

猜你喜欢

热点阅读