XMPP协议(-)

一、XML初识

现在比较流行的开放IM协议包括SIP、SIMPLE和XMPP(jabber)。对XMPP做一个简单介绍。

XMPP设计了一个在互联网上唯一的标识,用JID来表达。通常一个 JID 由三部分组成node@domain/resource 。和email很像,但比 email 的表达形式多了一个 /resource用来表达这个实体下的具体事物。例如ip地址和port的关系。通过不同的resource的区别使 XMPP 实现一个帐号在多处登录,例如,gtalk允许一个帐号的多处登录。

XMPP 规范的重要的通信协议是:如何把消息从一个 JID 发送到另一个 JID (message)。这有点像 email 协议,但不同的是,它强调了实时性和安全性(虽然不是必须的)。如果是两个domain下的JID的消息传输,传输的方式是 客户端0 -> XMPP服务器端 -> 客户端1 (c2s)。由服务器在中间进行转发!

如果JID可以在不同的domain下,这就需要 domain 间互通(s2s)。对于 IM 网络来说(XMPP 远不只用于 IM 协议)即为不同的IM服务间互通。不同服务商提供的XMPP服务只要遵循s2s标准,其天生的能够互联互通。也就是说使用zeuux提供的XMPP服务,能够加一个使用gtalk的联系人,并互相对话。此时的传输的方式是:user@domain0/resource –c2s–> domain0 XMPP服务器端 –s2s–> domain1 XMPP服务器端 –c2s–> user@domain1/resource。


对于 domain 下的 XMPP 服务的定义和发现,利用了 DNS 协议的SRV记录

例如,如果一个 XMPP 提供了的 s2s 服务,那么根据XMPP标准:

host -t srv  _xmpp-server._tcp.gmail.com
会发现 gmail.com 的 XMPP s2s 服务地址已经端口号 5269 。同样,也可以查询 _xmpp-server._tcp.ovi.com 查到Nokia OVI 的 XMPP s2s服务器地址。

对于一个 domain 下的c2s服务,
查询 _xmpp-client._tcp.gmail.com 可以查到我们client 登录 gtalk 的地址(c2s)。

例如连接asdf@example.com的XMPP帐户:
1. 解析 “_xmpp-client._tcp.example.com” ,获得连接的服务器和端口;
2. 如果失败,则解析 “_jabber._tcp.example.com”的SRV服务,这个主要针对老的服务器配置;
3. 如果还是失败,则客户端认为该域没有配置SRV记录,则直接解析”example.com”并使用默认端口5222连接。

XMPP 强调通讯的安全性,所以推荐的用户认证和握手都是建立在TLS和SASL之上(当然也可以采用明文方式)。

XMPP定义了消息的广播。也就是一个JID可以发布自己的“在线”消息 (presence)。而服务器来决定该发给谁。发送目标是由订阅关系(subscription)决定的。其它多个JID可以订阅某个JID的消息。对于IM来说,最常用的是上线下线和用户签名等状态变化都是通过presence向好友广播。同时由于IM的特点,这种presence消息往往占到IM总的消息量的1/3以上。

第三条即是客户端和服务器端的交互,这个是通过XML流(iq)来实现的。对于应用来说,设置签名,昵称,状态等都依赖于它。

XMPP 的核心协议(RFC 3920)即规定了以上三种通讯协议。

另外,因为XMPP基于XML,所以具有天生的可扩展性,XEP(XMPP Extensions,http://xmpp.org/extensions/)记录了XMPP目前最为活跃的基于core的扩展,现在已经有270个扩展,包括了BOSH、Jingle、Multi-User Chat等丰富的扩展

『From:http://blog.csdn.net/kaitiren/article/details/31397315』

二、深入XMPP

XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。XMPP协议采用的是客户端-服务器架构,所有从一个客户端发到另一个客户端的消息和数据都必须经过XMPP服务器转发,而且支持服务器间DNS的路由,也就是说可以构建服务器集群,XMPP的前身是一个开源组织制定的网络通信协议——Jabber,XMPP的核心是在网络上分片段发送XML流的协议,这个协议是XMPP的即时通讯指令的传递手段。 


XMPP的基本网络结构 ,xmpp定义了3个角色:Client,Server,Gateway

通信能够在这三者的任意两个之间双向发生。

服务器同时承担了客户端信息记录,连接管理和信息的路由功能。

网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。基本的网络形式是单客户端通过TCP/IP连接到单服务器,然后在之上传输XML。 
客户端利用xmpp(基于TCP/IP)访问server,传输的是XML 
Client--------Server------Client
    TCP            TCP            TCP


XMPP server:其内核是一个XMPP路由器,完成基本组件间的数据包交换和路由。
功能:
1.会话管理器:负责客户端会话认证,在线状态,用户联系表等
2.数据存储器(XDB):连接数据库系统,保持用户信息、通信日志等
3.连接器管理器:管理与客户端之间的连接
4.服务器连接器:管理xmpp服务器之间的连接
5.传输器:建立xmpp服务器与非xmpp服务器通信


所有从一个client到另一个client的jabber消息和数据都要通过xmpp server。

steps:
1.client连接到server
2.server利用本地目录系统的证书对其认证
3.client制定目标地址,让server告知目标状态
4.server查找,连接并进行相互认证
5.client间进行交互


统一的JID(jabber identifier)
JID=[ node”@” ] domain [ “/” resource ]
eg: cyber@cyberobject.com/res
domain:服务器域名
node: 用户名
resource:属于用户的位置或设备
一个用户可以同时以多种资源与同一个XMPP服务器连接


xmpp xml包括3个元素:简单示例:
<stram>
   <presence>
      <status/>
   </prensence>
   <message>
        <body/>
    </message>
    <iq>
    <bind/>
    </iq>
</stream>


<presence>-此元素确定用户的状态

eg:
<presence from=cyber1@jabber.org/contact to=cyber2@jabber.org/contact>
  <status>online</status>
</presence>


<message>-用于两个用户之间发送信息
<message from=cyber1@jabber.org/contact 
to=cyber2@jabber.org/contact
Type=“chat”>
  <body>Hello</body>
</message>


<iq>-信息/请求,是一个请求-响应机制,管理xmpp服务器上两个用户的转换,允许他们通过相应的xml格式的查询和响应
<iq
from=cyber1@jabber.org/contact 
Id=“id1” Type=“result”>  
</iq>

Iq的主要属性:type,包括:
Get:获取当前域值
Set:设置或替换get查询的值
Result:说明成功的响应了先前的查询
Error:查询和响应中出现的错误


XMPP 协议族基于TCP  XMPP采用SASL作为身份认证协议

SASL包含的信息:
<服务名>:XMPP
<初始序列>
<交换序列>
<安全层协商>


顺序:[TCP]?[TLS]?[SASL]?[XMPP]

 XMPP采用TLS的“START-TLS”扩展来为通信双方提供加密性和数据完整性服务

登录xmpp服务器过程示例 :

C—client      S—server


步骤:
1.client初始流给server
  C:
<stream:stream to="example.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0“ > 


2.server使用一个流标记作为响应发给client
  S:
<stream:stream from=‘cyber' xmlns='jabber:client' 
xmlns:stream='http://etherx.jabber.org/streams' id='a7747277-ad62-4813-b739-63504d6e1246' version='1.0' xml:lang='zh-cn‘ >


3.Server发送STARTTLS扩展给client,并带有认证机制与任何其他流特征
S:
<stream:features xmlns="http://etherx.jabber.org/streams">
  <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls" />
   <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
       <mechanism>PLAIN</mechanism>
       <mechanism>DIGEST-MD5</mechanism>
         </mechanisms>
         <compression xmlns="http://jabber.org/features/compress">
       <method>zlib</method>
         </compression>
   <auth xmlns="http://jabber.org/features/iq-auth" />
   <register xmlns="http://jabber.org/features/iq-register" />
</stream:features>


4. Client发送STARTTLS命令给Server
C:
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>


5.Server通知Client它被允许处理 
S:
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls" />
//Note:client与server TLS协商失败,server通知client TLS协商失败,并关闭流与TCP连接
<failure xmlns=“urn:ietf:params:xml:ns:xmpp-tls” />
</stream:stream>


6. 如果TLS协商成功,client初始化一个新流给server
 C:
<stream:stream to="example.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">


7.Server靠发送带有任何可利用流特征的流头作为响应
S:
<stream:stream from=‘cyber' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='a7747277-ad62-4813-b739-63504d6e1246' version='1.0' xml:lang='zh-cn'> 

<stream:features xmlns="http://etherx.jabber.org/streams">
       <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
        <mechanism>PLAIN</mechanism>
            <mechanism>DIGEST-MD5</mechanism>
        </mechanisms>
        <compression xmlns="http://jabber.org/features/compress">
               <method>zlib</method>
        </compression>
        <auth xmlns="http://jabber.org/features/iq-auth" />
        <register xmlns="http://jabber.org/features/iq-register" />
</stream:features>


8.Client选择一个认证机制
C:
<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">AGh4dwAx</auth>


9.Server通知client认证成功
S:

<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />
//Note:如果认证不成功,server通知client认证失败,并关闭流
<failure xmlns=“urn:ietf:params:xml:ns:xmpp-tls” >
  <temporary-auth-failure/>
</failure>


10.如果认证成功,client初始化一个新流给server
C:
<stream:stream to=“example" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">

</stream:stream>


11.Server依靠流头来响应client,并伴随有另外的特征
S:
<stream:stream from=’cyber' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='a7747277-ad62-4813-b739-63504d6e1246' version='1.0' xml:lang='zh-cn'> 

<stream:features xmlns="http://etherx.jabber.org/streams">
<compression xmlns="http://jabber.org/features/compress">
<method>zlib</method>
</compression>
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind" />
<session xmlns="urn:ietf:params:xml:ns:xmpp-session" />
</stream:features>


12.资源绑定:client发送一个类型为set的iq,并包含所需绑定的资源节点<resource/>
C:
<iq id="O193v-0" type="set">
  <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
   <resource>spark</resource>
  </bind>
</iq>


13.如果server为client产生了一个资源标识符或是接受了由客户端提供的资源标识符,它必须返回一个类型为result的iq节点给client,并必须包含<jid/>子节点,来为server决定的已连接资源指定全JID
S:
<iq xmlns="jabber:client" id="O193v-0"  type="result">
 <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
   <resource>spark</resource>
   <jid>username@cyber/spark</jid>
 </bind>
</iq>


14.Client向server请求session
C:

<iq id="O193v-1" type="set">
 <session xmlns="urn:ietf:params:xml:ns:xmpp- session"/>
</iq>


15.Server告知client,session已建立
S:

<iq xmlns="jabber:client" id="O193v-1" type="result">
<session xmlns="urn:ietf:params:xml:ns:xmpp-session" />
</iq>



From:http://blog.csdn.net/Kaitiren/article/details/29586565


posted @ 2016-09-27 00:38  cloudren2020  阅读(269)  评论(0编辑  收藏  举报