XMPP(Extensible Messaging and Presence Protocol,前称Jabber)是一种以 XML 为基础的开放式实时通信协议,关于它的协议细节,网上已经有太多分析文章,我这里就不再赘述(而且,我也不可能比别人解释的更清楚)。简单来看这个协议,我们只需要知道:
1,XMPP 的三种基本角色:客户端、服务器和网关,通信能够在这三者的任意两个之间双向发生。服务器端同时承担了客户端信息记录、连接管理和信息路由的功能。网关则承担着与异构系统的互联互通功能。在 RFC 3920 XMPP Core 中对 XMPP 网络结构有一个描述:
<pre>
C1—-S1—S2—C3
|
C2—-+–G1===FN1===FC1
</pre>
这里 C1,C2,C3 表示 XMPP 客户端;S1,S2 表示 XMPP 服务器;G1 表示网关,用来负责 XMPP 协议和外部聊天协议的转换;FN1 表示外部消息网络的服务器,FC1 表示外部网络客户端。
大家可能会奇怪,这里为什么需要一个网关呢。这要从 XMPP 的来源说起。1996 年 Mirabilis 公司推出了世界上第一个即时通信系统 ICQ,不到 10 年,IM 就成了最流行的应用之一,MSN、Gtalk、雅虎即时通、AIM、Adium、Pidgin 等各种软件如雨后春笋般涌现,但是这些服务之间没有统一的标准,不能互联互通,XMPP 的设计目的就是为了实现整个及时通信服务协议的互通,让 IM 成为继 WEB 和 Email 之后的互联网第三大服务。
2,XMPP 的消息格式。
XMPP 协议的所有消息都是 XML 格式的,这是 XMPP 协议的另一个充满历史意味的选择,想当年 SOA / SOAP 一时间爆发起来,很多消息交换协议都采用了 XML 格式,但是不想 XML 很快就成了「大数据」的代名词。在 RFC 3920 XMPP Core 中定义了两个基础概念,XML Stream 和 XML Stanza,XML Stream 是两个节点之间进行数据交换的容器,它定义了顶层的XML节点 <stream>;XML Stanza 则定义了实体消息的具体语义单元,在 XMPP 中定义了 3 个顶层消息:
2.1 Presence
用于确定用户的状态。消息结构举例如下(每个 XML 的 node 还会有很多其他 attribute,为了简单起见这里省略,下同):
<presence from=“[email protected]/contact” to=“[email protected]/contact”>
<status>online</status>
</presence>
2.2 Message
用于在两个用户之间发送消息。消息结构举例如下:
<message from=“[email protected]/contact” to=“[email protected]/contact” type=“chat”>
<body>hello</body>
</message>
2.3 IQ
信息/请求,是一个请求-响应机制,管理XMPP服务器上两个用户的转换,允许他们通过相应的XML格式进行查询和响应。
<iq from=“[email protected]/contact” id=“id11” type=“result”>
</iq>
3,XMPP 的交互流程。
XMPP 通过 TCP 传输了什么内容?在 QQ 里面,消息是使用二进制形式发送的,在 MSN 里面是采用纯文本指令加参数加换行符的形式发送的,而 XMPP 传输的即时通讯指令与他们相仿,只是协议的形式变成了 XML 格式的纯文本,这让解析更容易,方便了开发和查错,但是也带来了数据负载过重的缺点,而被人广为诟病。
XMPP 聊天的过程如下:
XMPP 协议的最主要的一点就是开放,不管是协议、客户端,还是 Server 端,都有成熟的实现方案。为了实际感受 XMPP 协议的聊天过程,我使用 asmack library + OpenFire 服务器搭建了一套完整的测试环境。
OpenFire 采用 Java 开发,是一个基于 XMPP 协议 的开源的实时协作服务器,它的安装和使用都非常简单,自带有一个内置的存储数据库(当然,你也可以使用独立数据库如Mysql等),并利用 Web 进行管理。其他类似的开源系统还有很多,eJabber、Tigase 也经常被用到。但是根据我们之前的经验,这些开源系统能支持的并发连接数都不高,要是有超过10万的用户同时连上来,对它们来说就快达到单机的瓶颈了,这时候一般都需要水平拆分,但是拆分之后服务器之间的 session 同步负担会大幅加重,对于性能又带来不小的抵消。所以这些系统大都被拿来做研究和测试用,很少见到大规模在生产环境中使用的。
好吧,我们还是来实际聊聊看。为了体现真实性,选取了程序员圈子里面较大概率可能发生的几段典型对话:
Case1-搭讪
猿:你吃饭了吗?
MM:吃了
猿:你在干什么呢?
MM:上网
猿:你那天气好吗?
MM:还可以
猿:你最近忙吗?
MM:不忙
猿:。。。。
猿:哦,这样啊,我就想知道你在干什么,那你继续忙吧,拜拜
MM:拜拜
Case2-请教
A:嘿 //是什么意思啊?
B:嘿.
A:呃 我问你//是什么意思?
B:问吧.
A:我刚才不是问了么?
B:啊?
A:你再看看记录…
B:看完了.
A:……所以//是啥?
B:所以什么?
A:你存心耍我呢吧?
B:没有啊 你想问什么?
Case3-约会
女:你能让这个论坛的人都吵起来,我今晚就跟你走.
某猿:PHP是最好的语言!
论坛一下炸翻了天,女:i服了u,我们走吧,你想干啥都行.
某猿:今天不行,我一定要说服他们,PHP必须是最好的语言
某女:…….
Case4-借钱
A:哥们儿,有钱吗?
B:有
A:借我点呗?
B:啊?你说什么?
A:借我点呗?
B:不是,上一句?
A:有钱吗?
B:没有
A:晕,程序重新请求一下,结果还不一样了!
实际结果如下,我在 Nexus5 上面运行一个 IM app,连接上我自己搭建的 openfire 服务器,然后模拟了上面几段对话,在几个参与者的前提下,消息实时性还挺好,但在系统设置-》网络流量中看到,整个聊天过程中该 app 消耗掉的网络流量高达 36KB,聊天记录的文本文件大小为 8KB,也就是说网络流量的 70% 都消耗在 XMPP 协议层了,这个数字正好吻合了维基百科上吐槽的数据冗余率。
最后测试下来看,我个人感觉是,对于移动互联网来说,省电、省流量是所有底层服务的一个关键技术指标,XMPP协议看起来已经落后移动互联网了。
1
erylee 2014-09-02 10:40:32 +08:00
嗯,个人觉得XMPP不适合,我们在开发SLIMPP,GitHub项目: https://github.com/slimpp/
|
3
ioth 2014-09-02 11:12:02 +08:00
关注,现在要做一个。
|
4
ahu 2014-09-02 11:16:03 +08:00
注册了下,貌似还不能用
|
5
erylee 2014-09-02 11:19:44 +08:00
@chmlai 基础协议刚开发完,比如iOS的CocoaMQTT, erlang的mqtt server。现在开发Android的一个Demo,0.1版本应该在10月发布,然后迭代协议到1.0
|
6
a2z 2014-09-02 11:22:16 +08:00
XMPP用的XML,overhead太大了,大部分情况下结构描述比信息本身都大,非常不适合在流量有限的移动环境中使用。
|
8
caoyue 2014-09-02 11:40:47 +08:00
XMPP 协议确实非常蛋疼,但是好处是足够完善,实现也很多,适合快速开发
|
9
allenforrest 2014-09-02 11:47:18 +08:00 1
SIP 也一样,开销非常大。
但我还是很推崇 XMPP,优势在协议完备性、各种实现的成熟度等等方面。 可以考虑在实现层面做一下改造,将 XMPP 报文在底层 TCP 传输时做一次编解码,转换成自定义的二进制格式,只需要改造一下 smack 库和 openfire 源码部分,对于上层应用开发来说完全透明,原来 smack 怎么用还是怎么用。 底层编码后的冗余数据大大减少,节省流量和功耗。 另外,考虑 XMPP 各种协议扩展较多,我们只需要针对最常用、最频繁的 XMPP 报文做编解码即可,其他不常用的仍然维持现有文本格式,对流量的贡献可控。 |
10
est 2014-09-02 11:49:45 +08:00
XMPP非常烂。离开了libjingle2的XMPP在桌面上都是一坨废物。
|
11
lithiumdroid 2014-09-02 11:52:54 +08:00
丰总,你还在写代码吗丰总
|
12
huoxiaochai 2014-09-02 13:00:54 +08:00 1
MQTT 值得你拥有!
|
13
jwfing OP @lithiumdroid 哈哈,写啊,我们公司工程师都写代码的。
|
14
jwfing OP 推荐大家考察一下我们推出的聊天服务: https://avoscloud.com/features/realtime-messaging.html
|
16
jwfing OP @shawngao 不是不是,我们有一个「小团队」在做 IM,主要负责的工程师是 https://twitter.com/Sunng
|
17
shawngao 2014-09-02 15:04:44 +08:00
@jwfing 这样啊,那顺便了解一下你们的IM用C/C++、Golang或者其他?这方面我也是比较感兴趣的,所以想特别了解一下。
|
18
pi1ot 2014-09-02 16:04:49 +08:00
xml上面zip一下应该会有改善吧
|
19
jwfing OP @shawngao 我们服务器端是用 Clojure 写的,整个 AVOS Cloud(http://avoscloud.com) 的后端和网站,都是 Clojure 写出来的:)
|
21
hussion 2014-09-02 17:00:03 +08:00
关注,我们暂时用socket.io实现,也在寻找比较靠谱的协议
|
22
railgun 2014-09-02 17:15:15 +08:00 1
不适合,首先传输用的是XML,构造和解析复杂,传输冗余大。
另外,它对不稳定的移动网络不友好,经常会发生丢消息的情况。 我认为成熟的移动IM,(或者根本不应该叫IM,移动网络的特点本身就决定了它不适合做即时通讯)应该同时兼容socket和HTTP,网络好的时候用socket保证实时性,网络差的时候用HTTP保证可靠性。 还有一个血的教训是,不要让它负责除了聊天之外的其他任何事情,好友关系处理、用户资料设置什么的,最好都自己另外弄一套。XMPP自带的扩展和传输都很麻烦 |
23
guoyang 2014-09-02 18:44:31 +08:00 via iPhone
作为一个趟过该浑水的人,我觉得自己搞私有协议远比xmpp好,因为用了之后你会发现里面的很多本来是好的东西,最后却变成了负担!特别对于移动网络
|
24
erylee 2014-09-02 19:08:48 +08:00
@railgun 非常有道理,我们直接JSON/HTTP+MQTT混合,网络好用MQTT推送,网络差通过HTTP同步。协议层面尽量支持Sync Pull和PUSH混合。
|
26
wenbinwu 2014-09-02 19:52:25 +08:00
hipchat?
|
27
llbgurs 2014-09-02 20:03:15 +08:00
可以看看我们的服务,基于mqtt的 yunba.io https://github.com/yunba
|
28
icyalala 2014-09-02 20:48:41 +08:00 1
XMPP太重,如果需求不复杂,socket.io自己定义下协议就够用了。
|
29
jwfing OP @icyalala 嗯,AVOS Cloud的聊天服务就是自定义协议,并且也支持socket.io,最后我们的体会是根本不需要那些「开放」且「重量级」的协议!
|
30
usufu 2014-09-03 09:00:48 +08:00
有没有支持视频聊天的协议?除了xmpp扩展以外?
|
31
pi1ot 2014-09-03 12:56:25 +08:00
文本沟通的话IRC协议就够了,只是IRC更面向群聊。
|
32
wupher 2014-09-03 14:01:11 +08:00
不适合。协议设计比较臃肿,XMPP协议最初设计时也没考虑移动端。
<message>本身是可丢弃的,掉了也就掉了。使用XMPP一般考虑的是服务端客户端有开源实现可抄,二来就是开放性了。 就现有开源实现来说,Erlang的那个ejabberd实现不太清楚,其它openFire, jabberd2感觉上量都有问题。群消息更是大深坑。 文件传输与音视频这块,其实XMPP也就负责握个手,该怎么走RTCP,到时还得怎么走。 量少浅尝可以,量大最终会开始动手改造。 倒是阅读XMPP协议蛮有趣的,没想到里面有这么多纯搞笑协议的RFC。比如XMPP-二进制版。 |
34
gfh110 2014-09-03 17:45:08 +08:00 1
大家应该看下xmpp产生的历史。当时它的目标是提供一种通用的协议来试不同厂商的im可以互相通信。
它的性能并不好,而且因为是xml协议并不适用目前国内还对流量敏感的用户,并发量也上不去 |
35
citysofa 2014-09-03 17:50:45 +08:00
不适合
|
36
siteshen 2014-09-03 18:42:36 +08:00
坐等IM开源……
|
37
popatry 2014-09-04 01:56:13 +08:00 1
> 整个聊天过程中该 app 消耗掉的网络流量高达 36KB,聊天记录的文本文件大小为 8KB,也就是说网络流量的 70% 都消耗在 XMPP 协议层了,这个数字正好吻合了维基百科上吐槽的数据冗余率。
首先,其实浪费的带宽并没有你想象那么高比例。因为你没有考虑IP层和TCP层的带宽占用。我估计这种短小聊天信息如果有8KB,那么TCP/IP包头加起来恐怕也有10KB到20KB了。那么算上这些带宽占用,XMPP协议层占用的带宽也就在50%左右了。 其次,XMPP基于XML协议层格式繁琐,但信息量并不高,所以如果要压缩,那么压缩率就会很高。XMPP协议通常要通过TLS加密,可以启用TLS压缩选项。 最后,无论使用任何协议,文本聊天都不会占用很多带宽,稍微浪费一点,问题不大。 |
38
yunbaIO 2014-09-04 11:24:47 +08:00 1
不适合。虽然说XMPP本身是一个非常完整的协议,而且扩展性相当好,也有一些很好的Broker。但它并不适合用来做移动IM。其中一个劣势@jwfing 已经提到,就是它本身协议承载数据比例太低,差不多70%的流量都是消耗在标签上。另一个麻烦的问题就是它的延迟大。我们试验过用XMPP来做一个简单的Connect和用户认正,不仅要用1K的流量,还需要5-7次的交互,换句话说,一个登录就是秒级的延迟(移动互联网一个环回大概就是400、500毫秒)。另一个缺点就是XMPP的编解码也是很重,因为它是纯文本的解析器,你要用纯文本去做,不管是编码还是解码都是比较重的,在移动环境下合适。
推荐用MQTT协议,它是二进制协议,而且本身非常精简,做移动网络环境下做IM非常合适,省电省流量。它的做法是一个订阅/发布系统,拿到权限的人就可以往频道里发消息,任何在这个频道里的人就可以收到。MQTT还是开放协议,有很多开源实现,可以用它的开源实现搭个环境来玩一玩。另外很重要的一点就是它的扩展很方便,它原来就留了两个两个命令字,再加上它协议头本身很轻,在它的扩展命令字上做一些简单的事情就可以扩展出很多命令字。 我们云巴yunba.io是基于MQTT协议做双向消息实时推送,也支持Socket.io。开发者可以使用云巴,快速搭建包括移动IM以内的各类型实时应用。可以稳定支持千万级亿级海量用户。我们设立多处主干机房,全国范围内消息延迟在0.2s以内。 我们也投入了大量时间精力研究实践实时海量数据通讯、统计、存储等问题。之前创始人还在ArchSummit上就这方面做了的分享,题目就是实时系统架构和实践,有兴趣的可以戳http://t.cn/RhUxmwN看视频,全程干货,当时也提到了协议选择的问题。 对了,还有一个基于云巴产品开发的移动IM开源Demo,或许有用哈,Github地址http://t.cn/RPxwZjQ |
39
loddit 2014-09-05 09:08:28 +08:00
之前用过一阵子XMPP,感觉除了大家提到的XML冗余之外,还有一些限制它适用性的地方。
最主要就是它有一下自己的业务设计,比如加入room需要客户端发送presence,需要先主动获取 roster 才能获取好友状态的更新。叫 一般来讲采用 XMPP 主要的好处就是可以直接使用很多开源的产品。但是因为本身也算比较复杂,这些产品上做一些自己的定制就没那么容易。 在移动端我不熟悉,我觉得如果使用第三方的平台实现实时通信可能是比较快速的选择。 ps ejabberd 是比较有名的 erlang 实现,实现的xmpp协议比较全,而且性能貌似是目前最好的吧? 不如 openFire 吗? |
40
Wichna 2015-07-27 13:10:47 +08:00
好老的文了。很不错,顶一下。
|