XMPP
2010-07-05 21:30:03 阿炯

1、什么是XMPP ?
XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。它在促进服务器之间的准即时操作。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。标准化的核心结果分为两部分:
核心的XML流传输协议
基于XML流传输的即时通讯扩展应用
XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性,使得XMPP的协议能够非常出色。XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的,与其他业已得到广泛使用的即时通讯协议,诸如AIM,QQ等有功能完整,完善等先进性。XMPP的扩展协议Jingle使得其支持语音和视频。

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

3、XMPP通过TCP传什么了?
传输的是与即时通讯相关的指令。在以前这些命令要么用2进制的形式发送(比如QQ),要么用纯文本指令加空格加参数加换行苻的方式发送(比如MSN)。而XMPP传输的即时通讯指令的逻辑与以往相仿,只是协议的形式变成了XML格式的纯文本。这不但使得解析容易了,人也容易阅读了,方便了开发和查错。而XMPP的核心部分就是一个在网络上分片断发送XML的流协议。这个流协议是XMPP的即时通讯指令的传递基础,也是一个非常重要的可以被进一步利用的网络基础协议。所以可以说,XMPP用TCP传的是XML流。

4、所谓的XML流是什么样子的?

以文档的观点来看,客户端或服务器发送的所有XML文本连缀在一起,从到构成了一个完整的XML文档。其中的stream标签就是所谓的XML Stream。在与中间的那些...这样的XML元素就是所谓的XML Stanza(XML节)。XMPP核心协议通信的基本模式就是先建立一个stream,然后协商一堆安全之类的东西,中间通信过程就是客户端发送XML Stanza,一个接一个的。服务器根据客户端发送的信息以及程序的逻辑,发送XML Stanza给客户端。但是这个过程并不是一问一答的,任何时候都有可能从一个方发信给另外一方。通信的最后阶段是关闭流,关闭TCP/IP连接。

XMPP(Extensible Messaging and Presence Protocol,前称Jabber)是一种以XML为基础的开放式即时通信协议,是经由互联网工程工作小组(IETF)通过的互联网标准。XMPP因为被Google Talk应用而被广大网民所接触。

历史

Jeremie Miller于1998年开始了这个项目。第一个公开版本于2000年5月发行。这个项目的主要产品是jabberd,XMPP的服务器端软件。它既可以创建私人的XMPP 网络,也可以加入全球的公共XMPP网络。XMPP的关键特色是,分布式的即时通信系统,以及使用XML流。

标准化的Jabber已经由IETF XMPP协议(RFC3920)。

Jabber是一个开放源码形式组织产生的网络即时通信协议。XMPP原本是为Instant Messenger而量身定制,但由于XML Stanza本身是XML元素,在基于XML灵活发展的特性下,使得XMPP也可以适用其他方面,已经得到了IETF的批准。XMPP与IMPP、PRIM、SIP(SIMPLE)合称四大IM协议主流,在此4大协议中,XMPP是最灵活的。

2005 年,Google发布了Google Talk,这是一个IP电话及即时通信的服务,即时通讯功能采用了开放的XMPP。预计这将对XMPP社区起很大的推动作用。初期此服务不支持服务器到服务器的通讯功能,所以未能完全发挥XMPP的分布式特色;虽然任何XMPP客户端都能连接到Google Talk,但是用户若欲登录Google Talk,必须拥有Google Talk帐号(即Gmail帐号),而用户也无法与公共XMPP网络的用户对谈。自2006年1月17日起,服务器到服务器的通信激活了,Google Talk用户可与其他XMPP公共网络的用户对谈。

2007 年,年的Jabber软件基金会已经成为XMPP标准基金会。

XMPP是一种基于XML的协议,它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。而且XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。

XMPP系统特点

    XMPP 协议是公开的,由JSF开源社区组织开发的。XMPP 协议并不属于任何的机构和个人,而是属于整个社区,这一点从根本上保证了其开放性。
    XMPP 协议具有良好的扩展性。在XMPP 中,即时消息和到场信息都是基于XML 的结构化信息,这些信息以XML 节(XML Stanza)的形式在通信实体间交换。XMPP 发挥了XML 结构化数据的通用传输层的作用,它将出席和上下文敏感信息嵌入到XML 结构化数据中,从而使数据以极高的效率传送给最合适的资源。基于XML 建立起来的应用具有良好的语义完整性和扩展性。
    分布式的网络架构。XMPP 协议都是基于Client/Server 架构,但是XMPP协议本身并没有这样的限制。网络的架构和电子邮件十分相似,但没有结合任何特定的网络架构,适用范围非常广泛。
    XMPP 具有很好的弹性。XMPP 除了可用在即时通信的应用程序,还能用在网络管理、内容供稿、协同工具、档案共享、游戏、远端系统监控等。
    安全性。XMPP在Client-to-Server通信,和Server-to-Server通信中都使用TLS (Transport Layer Security)协议作为通信通道的加密方法,保证通信的安全。任何XMPP服务器可以独立于公众XMPP网络(例如在企业内部网络中),而使用SASL及TLS等技术更加增强了通信的安全性。如下图所示:



XMPP的架构

XMPP的基本网络架构包含三元素:客户端、服务器、网关,具体如下图:



    服务器:承担客户端信息记录、连接管理和信息的路由功能。
    网关:承担着异构即时通信系统的互联互通,包括(SMS、MSN、ICQ等)。


特点

优点
开放—XMPP协议是自由、开放、公开的,并且易于了解。而且在客户端、服务器、组件、源码库等方面,都已经各自有多种实现。
标准—互联网工程工作小组(IETF)已经将Jabber的内核XML流协议以XMPP之名,正式列为认可的即时通信及Presence技术。而XMPP的技术规格已被定义在RFC 3920及RFC 3921。任何IM供应商在遵循XMPP协议下,都可与Google Talk实现连接。
证实可用—第一个Jabber(现在XMPP)技术是Jeremie Miller在1998年开发的,现在已经相当稳定;数以百计的开发者为XMPP技术而努力。今日的互联网上有数以万计的XMPP服务器运作著,并有数以百万计的人们使用XMPP即时传讯软件。
分布式—XMPP网络的架构和电子邮件十分相像;XMPP内核协议通信方式是先建立一个 stream,XMPP以TCP传递XML数据流,没有中央主服务器。任何人都可以运行自己的XMPP服务器,使个人及组织能够掌控他们的即时传讯体验。
安全—任何XMPP协议的服务器可以独立于公众XMPP网络(例如在企业内部网络中),而使用SASL及TLS等技术的可靠安全性,已内置于内核XMPP技术规格中。
可扩展—XML命名空间的威力可使任何人在内核协议的基础上建造客制化的功能;为了维持通透性,常见的扩展由XMPP Standards Foundation。
弹性佳—XMPP除了可用在即时通信的应用程序,还能用在网络管理、内容供稿、协同工具、文件共享、游戏、远程系统监控等。
多样性—用XMPP协议来建造及布署即时应用程序及服务的公司及开放源码计划分布在各种领域;用XMPP技术开发软件,资源及支持的来源是多样的,使得使你不会陷于被“绑架”的困境。

缺点
* 数据负载太重:随着通常超过70%的XMPP协议的服务器的数据流量的存在和近60%的被重复转发,XMPP协议目前拥有一个大型架空中存在的数据提供给多个收件人。新的议定书正在研究,以减轻这一问题。
* 没有二进制数据:XMPP协议的方式被编码为一个单一的长期XML文件,因此无法提供修改二进制数据。因此, 文件传输协议一样使用外部的HTTP。如果不可避免,XMPP协议还提供了带编码的文件传输的所有数据使用的Base64。至于其他二进制数据加密会话(encrypted conversations)或图形图标(graphic icons)以嵌入式使用相同的方法。

Decentralization 和addressing

每个用户在网络上有一个独特的Jabber ID(通常缩写为JID)。为了避免需要一个中央服务器的目录名,该JID的结构像一个 e-mail地址的用户名和一个的DNS地址的服务器的用户分开居住的符号(@),如username@domain.com。

与其他协议互联

各IM之间的互传

XMPP协议的另一功能是运输(transports),也被称为网关(gateways),可允许用户通过网络使用其它协议。这可以是其他的即时通信协议,也可以是不同协议,如短信(SMS)或电子邮件。

XMPP协议通过HTTP运输

在原来的规格,XMPP协议可以使用HTTP的方式有两种:轮询(polling)[3]与绑定(binding)。轮询现在不推荐,基本上,轮询意味着HTTP邮件存储在服务器端的数据库会受到牵累与延迟(fetched and posted),当一个XMPP客户端调用HTTP的GET和POST的要求时。

由于客户端使用HTTP,大多数防火墙允许客户端获取和留言没有任何障碍。因此在此情况下(scenarios)的TCP端口使用XMPP协议的被拦截,一台服务器能倾听(listen)正常的HTTP端口和交通(traffic)应通过没有任何问题。

实现

XMPP协议是由大量的XMPP协议的客户端,服务器和程序库。主要的文章包含了几个XMPP协议清单客户的多种平台。

XMPP的协议

XMPP 是一种很类似于http协议的一种数据传输协议,它的过程就如同“解包装–>包装”的过程,用户只需要明白它接受的类型,并理解它返回的类型,就可以很好的利用xmpp来进行数据通讯。

1)、XML流传输协议

XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性,使得XMPP的协议能够非常漂亮。XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的,与其他业已得到广泛使用的即时通讯协议,诸如AIM,QQ等有功能完整,完善等先进性。XMPP的扩展协议Jingle使得其支持语音和视频。XMPP的官方文档时RFC 392。

客户端开始和XMPP服务器会话,会打开一个长时间的TCP连接,然后和服务器协商一个流。一旦你和你的服务器建立了一个XML流,你和你的服务器可以通过流交换三个特殊的XML片段,这些片段称为XML节。是XML中最有意义的基本单元,而且一旦你已建立一个XML流,你可以通过流发送无数个节。

    客户端与服务器通信的过程中,服务器必须允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。
    服务器到服务器的通信过程中,服务器必须用一个TCP连接向对方发送XML节,另一个TCP连接(由对方初始化)接受对方的XML节,一共两个TCP连接。

举例看看所谓的XML流是什么样子的?

    客户端:<?xml version=’1.0′?><stream:stream to=’example_com’ xmlns=’jabber:client’ xmlns:stream=’http_etherx_jabber_org/streams’ version=’1.0′>
    服务器:<?xml version=’1.0′?><stream:stream from=’example_com’ id=’someid’ xmlns=’jabber:client’ xmlns:stream=’http_etherx_jabber_org/streams’ version=’1.0′>
    …其他通信…
    客户端:<message from=’juliet_example_com’ to=’romeo_example_net’ xml:lang=’en’>
    客户端:<body>Art thou not Romeo, and a Montague?</body>
    客户端:</message>
    服务器:<message from=’romeo_example_net’ to=’juliet_example_com’ xml:lang=’en’>
    服务器:<body>Neither, fair saint, if either thee dislike.</body>
    服务器:</message>
    客户端:</stream:stream>
    服务器:</stream:stream>

以文档的观点来看,客户端或服务器发送的所有XML文本连缀在一起,从<stream>到</stream>构成了一个完整的XML文档。其中的stream标签就是所谓的XML Stream。在<stream>与</stream>中间的那些<message>…</message>这样的XML元素就是所谓的XML Stanza(XML节)。XMPP核心协议通信的基本模式就是先建立一个stream,然后协商一堆安全之类的东西,中间通信过程就是客户端发送XML Stanza,一个接一个的。服务器根据客户端发送的信息以及程序的逻辑,发送XML Stanza给客户端。但是这个过程并不是一问一答的,任何时候都有可能从一方发信给另外一方。通信的最后阶段是</stream>关闭流,关闭TCP/IP连接。

2)、XMPP地址格式

因为xmpp通讯实在网络上,所以每个xmpp实体都需要一个地址,称为JabberID(JID)。一个合法的JID包括一组排列好的元素,包括域名(domain identifier), 节点名(node identifier), 和资源名(resource identifier)。node@domain/resource这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接对资源。一个JID的每一个合法部分的长度不能超过1023字节。
域名是一个主要的ID,并且是JID中唯一必须的元素。(一个纯粹的域名也是一个合法的JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现xml转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,也可能是一个服务器子域名地址。
节点名是一个可选的第二ID,放在域名之前并用符号“@”分开。它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然也可能表示其他实体(如聊天室中的一个房间)。
资源名是一个可选的第三ID,它放在域名后面并由“/”分开,资源名可以跟在node@domain后面也可以跟在后面。它通常表示一个特定的会话连接,或者附属于某个节点ID实体相关实体的对象。

3)、XMPP消息格式

在 RFC 3920 XMPP Core 中定义了两个基础概念,XML Stream 和 XML Stanza,XML Stream 是两个节点之间进行数据交换的容器,它定义了顶层的XML节点;XML Stanza 则定义了实体消息的具体语义单元,在XMPP中定义了3个顶层消息:Message、Presence和IQ。

<Message>

Message是一种基本推送消息方法,它不要求响应。主要用于IM、groupChat、alert和notification之类的应用中。

主要属性如下:

    type属性,它主要有5种类型:
        normal:这种消息类型立即被传递或被服务器离线存储,并被客户端以任何聊天或群聊对话外的独立消息来处理。这个类型是默认值。类似于email,主要特点是不要求响应。
        chat:chat消息类型在“聊天会话”中通常在相对短的时间内以突发消息发送。即时消息客户端在一对一的对话界面中显示这些信息。类似于qq里的好友即时聊天,主要特点是实时通讯。
        groupchat:XMPP服务器通常将路由类型为groupchat的消息路由到一个拥有多个聊天室的专门组件或模块,并且这个组件产生一个向外的消息给房间的每一个人。类似于聊天室里的群聊。
        headline:headline消息通常不被离线存储,因为他们是临时性的。另外,XMPP服务器经常传递headline类型的消息到所有和账户关联的在线设备(至少priority值为非负的)。用于发送alert和notification。
        error:error类型的消息是为了应答先前发送的消息而被发送出去的,以指示和先前消息有关的错误发送(接收人不出席,此时不能发送消息等)。如果发送message出错,发现错误的实体会用这个类别来通知发送者出错了。
    to属性:标识消息的接收方。
    from属性:指发送方的名字或标示。为防止地址外泄,这个地址通常由发送者的server填写,而不是发送者。
    载荷(payload):此元素包含了要提交给目标用户的信息。例如body,subject,thread

消息结构如下:
<message from="abc@jabber.org/contact" to="def@jabber.org/contact" type="chat">
    <body>hello</body>
</message>

在聊天中加入不知道聊天对象的状态会让人误以为对方已经离线或不想搭理人,未免让人心中有所失落。比如,你和你的女友聊天,你问:“亲爱的,今天都干啥了”,你的女友很兴奋,她有很多话要告诉你,由于打字的时间太久让你觉得她不爱你….好嘛,这样的聊天是不是很虐心….然后,办法还是有的,你需要在你的IM系统中得到聊天状态的通告,定义聊天状态通告[XEP-0085]。

聊天状态

    Starting:人开始一个对话,但是你还没有参与进来
    Active:正参与在对话中,当前你没有组织你的消息,而是在关注
    Composing:正在组织一个消息
    Paused:开始组织一个消息,但由于某个原因而停止组织消息
    Inactive:一段时间里没有参与这个对话
    Gone:参与的这个对话已经结束

示例:
<message from="abc@jabber.org/contact" to="def@jabber.org/contact" type="chat">
    <body>hello</body>
    <starting xmlns="http://jabber.org/protocol/chatstates"/>
</message>

<Presence>

presence用来表明用户的状态,如:online、away、dnd(请勿打扰)等。当改变自己的状态时,就会在stream的上下文中插入一个Presence元素,来表明自身的状态。要想接受presence消息,必须经过一个叫做presence subscription的授权过程。

属性:

type属性,非必须。有以下类别
        subscribe:订阅其他用户的状态
        probe:请求获取其他用户的状态
        unavailable:不可用,离线(offline)状态
to属性:标识消息的接收方。
from属性:指发送方的名字或标示。
载荷(payload):
show:
        chat:聊天中
        away:暂时离开
        xa:eXtend Away,长时间离开
        dnd:勿打扰
status:格式自由,可阅读的文本。也叫做rich presence或者extended presence,常用来表示用户当前心情,活动,听的歌曲,看的视频,所在的聊天室,访问的网页,玩的游戏等等。
priority:范围-128~127。高优先级的resource能接受发送到bare JID的消息,低优先级的resource不能。优先级为负数的resource不能收到发送到bare JID的消息。

消息结构如下:

<presence from="abc@jabber.org/contact" to="def@jabber.org/contact">
    <status>online</status>
</presence>

<IQ>(Info / Query)

一种请求/响应机制,从一个实体从发送请求,另外一个实体接受请求,并进行响应。例如,client在stream的上下文中插入一个元素,向Server请求得到自己的好友列表,Server返回一个,里面是请求的结果。

主要的属性是type。发送IQ节的实体必须总是接收一个回复(通常由目的接收者或接受者的服务器产生)。请求和应答通过使用id属性跟踪,id属性由请求实体生成,并被包含在应答的实体中。

Get : 请求实体信息,例如请求注册一个账户(类似于HTTP GET)。
Set : 请求实体提供一些信息或作出一个请求(类似于HTTP POST或PUT)。
Result : 应答实体返回get操作的结果(例如一个实体必须提供信息用来注册账户),或者确认一个set请求(类似于一个HTTP200状态码)。
Error: 应答实体或一个中间实体,例如XMPP服务器,通知请求实体它不能处理get或set请求(例如,因为请求的格式不正确,请求实体无权执行该操作等)。早期在HTTP中使用的数字错误代码已被可扩展错误条件的XML元素取代。

消息结构如下:

<iq from="abc@jabber.org/contact" id=“id11” type=“result”></iq>

说到这里,就不得不说XMPP一只被吐槽的缺点:由于使用XML,网络流量的 70% 都消耗在 XMPP 协议层了。基于此WhatsApp在此基础上改进了XMPP协议。

该文章最后由 阿炯 于 2020-08-11 10:10:21 更新,目前是第 8 版。