【转】XMPP协议学习笔记
Android消息推送
所谓的消息推送就是从服务器端向移动终端发送连接,传输一定的信息。比如一些新闻客户端,每隔一段时间收到一条或者多条通知,这就是从服务器端传来的推送消息;还比如常用的一些IM软件如微信、GTalk等,都具有服务器推送功能。
推送方法如下:
1)通过SMS进行服务器端和客户端的交流通信。
在Android平台上,你可以通过拦截SMS消息并且解析消息内容来了解服务器的意图,可以实现完全的实时操作。但是问题是这个方案的成本相对比较高,且依赖于运营商。
2)循环主动定时获取
这种方法需要客户端来做一个定时或者周期性的访问服务器端接口,以获得最新的消息。轮询的频率太慢可能导致某些消息的延迟,太快则会大量消耗网络带宽和电池。
3)持久连接
这个方案可以解决由轮询带来的性能问题,但是还是会消耗手机的电池。我们需要开一个服务来保持和服务器端的持久连接(苹果就和谷歌的C2DM是这种机制)。但是对于Android系统,当系统可用资源较低,系统会强制关闭我们的服务或者是应用,这种情况下连接会强制中断。(Apple的推送服务之所以工作的很好,是因为每一台手机仅仅保持一个与服务器之间的连接,事实上C2DM也是这么工作的。即所有的推送服务都是经由一个代理服务器完成的,这种情况下只需要和一台服务器保持持久连接即可。C2DM=CloudtoDeviceMessaging)。
相比之下第三种还是最可行的。为软件编写系统服务或开机启动功能;或者如果系统资源较低,服务被关闭后可以在onDestroy()方法里面再重启该服务,进而实现持久连接的方式。
C2DM内置于Android的2.2系统上,无法兼容老的1.6到2.1系统;且依赖于Google官方提供的C2DM服务器,由于国内的网络环境,这个服务经常不可用。
建立在TCP协议之上的XMPP协议,不仅可提供可这种持久连接的功能,能实现服务器和客户机的双工通信,还能不依赖与系统版本和google服务器的限制,提供了比较好的解决方案。
2.XMPP协议
XMPP全称ExtensibleMessagingandPresenceProtocol,前身是Jabber项目,是一种以XML为基础的开放式即时通讯协议。XMPP因为被GoogleTalk和网易泡泡应用而被广大网民所接触。XMPP的关键特色是,分散式的即时通讯系统,以及使用XML串流。XMPP目前被IETF国际标准组织完成了标准化工作。
Androidpushnotification(androidpn)是一个基于XMPP协议的java开源实现,它包含了完整的客户端和服务器端。该服务器端基本是在另外一个开源工程openfire基础上修改实现的。
androidpn客户端需要用到一个基于java的开源XMPP协议包asmack,这个包同样也是基于openfire下的另外一个开源项目smack,不过我们不需要自己编译,可以直接把androidpn客户端里面的asmack.jar拿来使用。客户端利用asmack中提供的XMPPConnection类与服务器建立持久连接,并通过该连接进行用户注册和登录认证,同样也是通过这条连接,接收服务器发送的通知。
androidpn服务器端也是java语言实现的,基于openfire开源工程,不过它的Web部分采用的是spring框架,这一点与openfire是不同的。Androidpn服务器包含两个部分,一个是侦听在5222端口上的XMPP服务,负责与客户端的XMPPConnection类进行通信,作用是用户注册和身份认证,并发送推送通知消息。另外一部分是Web服务器,采用一个轻量级的HTTP服务器,负责接收用户的Web请求。服务器的这两方式,意义非凡:当相应的TCP端口被防火墙封闭,可以使用轮询的方式进行访问,因此又有助于通过防火墙。
- 即时通讯技术简介
即时通讯技术(IM)支持用户在线实时交谈。如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈的内容。大多数常用的即时通讯发送程序都会提供各种各样的功能:
- 即时通讯 - 在用户和在线朋友之间来回发送信息
- 聊天 - 创建用户与朋友或工友的自定义聊天室
- 网页链接 - 共享用户喜爱的网址
- 支持图片 - 浏览朋友计算机中的图片
- 支持声音 - 给朋友播放音乐
- 支持文件传输 - 直接将文件发送给朋友,以便于共享
- 交谈 - 使用 Internet,而不是电话,与朋友们进行真正的交谈
- 影音串流内容 - 实时或准实时的股市行情或新闻
有许多的IM系统,如 AOL IM、Yahoo IM、 MSN IM还有我们熟悉的QQ,它们最大的区别在于各自通讯协议的实现,所以即时通讯技术的核心在于它的传输协议,协议用来说明信息在网络上如何传输,如果有了统一的传输协议,那么应当可以实现各个IM之间的直接通讯,为了创建即时通讯的统一标准,人们经过了多次尝试:IETF 的对话初始协议(SIP)和即时通讯对话初始协议和表示扩展协议(SIMPLE)、应用交换协议(APEX)、显示和即时通讯协议(PRIM)及基于 XML 且开放的可扩展通讯和表示协议(XMPP)协议(常称为 Jabber 协议)。人们多次努力,试图统一各大主要 IM 供应商的标准(AOL、Yahoo 及 Microsoft),但无一成功,且每一种 IM 仍然继续使用自己所拥有的协议。
- 几种IM协议标准简介
IMPP主要定义必要的协议和数据格式,用来构建一个具有空间接收、发布能力的即时信息系统。到目前为止,这个组织已经出版了三个草案RFC,但主要的有两个:一个是针对站点空间和即时通讯模型的(RFC2778);另一个是针对即时通讯/空间协议需求条件的(RFC2779)。RFC2778是一个资料性质的草案,定义了所有presence和IM服务的原理。RFC2779定义了IMPP的最小需求条件。另外,这个草案还就presence服务定义了一些条款,如运行的命令、信息的格式,以及presence服务器如何把presence的状态变化通知给客户。
SIMPLE是目前为止制定的较为完善的一个。SIMPLE和XMPP两个协议,都符合RFC2778和RFC2779。SIMPLE计划利用SIP来发送presence信息。SIP是IETF中为终端制定的协议。SIP一般考虑用在建立语音通话中,一旦连接以后,依*如实时协议(RTP)来进行实际上的语音发送。但SIP不仅仅能被用在语音中,也可以用于视频。SIMPLE被定义为建立一个IM进程的方法。SIMPLE在2002年夏季得到额外的信任,目前,微软和IBM都致力于在它们的即时通讯系统中实现这个协议。
SIMPLE小组致力于进程模式的操作,这将提升运行效率,使基于SIP的机制能够进行会议和三方电话交谈控制,也考虑到能和未来提供的许多新特性实现兼容并提升表现能力。有了进程模式,SIMPLE使用SIP来建立一次进程,再利用SDP(进程描述协议)来实际传输IM数据。
XMPP是一种基于XML的协议,它继承了在XML环境中灵活的发展性。这表明XMPP是可扩展的。可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。
XMPP目前在免费源代码开放Jabber IM系统中被广泛采用。2002年,这个产品有超过5万的下载量。XMPP拥有成千的Jabber开发者,以及大约数万台配置的服务器和超过百万的终端用户。- XMPP概述
XMPP: The Extensible Messaging and Presence Protocol
中文全称:可扩展通讯和表示协议
简介:可扩展通讯和表示协议 (XMPP) 可用于服务类实时通讯、表示和需求 - 响应服务中的 XML 数据元流式传输。XMPP 以 Jabber 协议为基础,而 Jabber 是即时通讯中常用的开放式协议。XMPP is the IETF's formalization of the base XML streaming protocols for instant messaging and presence developed within the Jabber open-source community in 1999
XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。它在促进服务器之间的准即时操作。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。标准化的核心结果分为两部分;
核心的XML流传输协议
基于XML FreeEIM流传输的即时通讯扩展应用
XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性,使得XMPP的协议能够非常漂亮。
XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的,与其他业已得到广泛使用的即时通讯协议,诸如AIM,QQ等有功能完整,完善等先进性。
XMPP的扩展协议Jingle使得其支持语音和视频。
XMPP的官方文档时RFC 3920.
- XMPP的基本结构
XMPP中定义了三个角色,客户端,服务器,网关。通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录,连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。基本的网络形式是单客户端通过TCP/IP连接到单服务器,然后在之上传输XML。
- XMPP通过TCP传的是什么
传输的是与即时通讯相关的指令。在以前这些命令要么用2进制的形式发送(比如QQ),要么用纯文本指令加空格加参数加换行苻的方式发送(比如MSN)。而XMPP传输的即时通讯指令的逻辑与以往相仿,只是协议的形式变成了XML格式的纯文本。这不但使得解析容易了,人也容易阅读了,方便了开发和查错。而XMPP的核心部分就是一个在网络上分片断发送XML的流协议。这个流协议是XMPP的即时通讯指令的传递基础,也是一个非常重要的可以被进一步利用的网络基础协议。所以可以说,XMPP用TCP传的是XML流。
- XMPP的相关文档
推荐一个包含XMPP相关资料的百度空间:http://hi.baidu.com/jabber/home
XMPP官网:http://xmpp.org/
Jabber官网,包含许多XMPP的实现:http://www.jabber.org/
- 下一篇详细介绍XMPP协议相关细节
- IM的实现原理
在我最初学习编程的时候,曾经用JAVA实现了一个最简单版的IM通讯,即通过Socket建立两台电脑之间的连接,然后发送IO流来进行即时通讯,我们现在所使用的IM软件尽管看上去非常复杂,但是基本的原理和以上的差不多,无非是采用服务器<>客户端的架构,通过登陆到服务器来获取个人资料和好友,然后聊天时直接通过IP和好友进行即时通讯。
- XMPP协议的网络架构
XMPP是一个典型的C/S架构,而不是像大多数即时通讯软件一样,使用P2P客户端到客户端的架构,也就是说在大多数情况下,当两个客户端进行通讯时,他们的消息都是通过服务器传递的(也有例外,例如在两个客户端传输文件时).采用这种架构,主要是为了简化客户端,将大多数工作放在服务器端进行,这样,客户端的工作就比较简单,而且,当增加功能时,多数是在服务器端进行.XMPP服务的框架结构如下图所示.XMPP中定义了三个角色,XMPP客户端,XMPP服务器、网关.通信能够在这三者的任意两个之间双向发生.服务器同时承担了客户端信息记录、连接管理和信息的路由功能.网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信)、MSN、ICQ等.基本的网络形式是单客户端通过TCP/IP连接到单服务器,然后在之上传输XML,工作原理是:
- 节点连接到服务器;
- 服务器利用本地目录系统中的证书对其认证;
- 节点指定目标地址,让服务器告知目标状态;
- 服务器查找、连接并进行相互认证;
- 节点之间进行交互。
XMPP协议的传输是通过XML文件来传输的,并且不是类似于QQ的点对点通讯,而是客户端到服务器再到客户端的方式来实现,以上过程的一个简单的XMPP通讯流程可以如下:
- 首先,由客户端连接到服务器,客户端通过IO流发送一段XML文件,在文件中包含了自身的用户名和密码。
- 服务器端接收到客户端的XML文件,从中获取用户名和密码进行验证,如果验证成功,服务器会发送一个XML文件给客户端表明已经登录成功。
- 登陆成功后,客户端可以通过发送一个获取好友名单的XML文件,服务器会将当前用户的好友以XML文件传到客户端。
- 客户端选择一个好友,向其发送信息(其实是向服务器发送,服务器收到后会转发给对应的好友),好友收到。
通过以上的流程,一此基本的通讯得以达成。
(上图为XMPP的一个实现Openfire+Smack+Spark的实现)
- XMPP协议的一些概念
通过以上简介,我们了解了XMPP协议的基本流程,下面来了解一个XML中一些基本的概念。
- XMPP地址
一个实体在XMPP网络结构中被称为一个节点,它有唯一的标示符jabber identifier(JID),即实体地址,用来表示一个用户,但是也可以表示其他内容,例如一个聊天室.一个有效的JID包括一系列元素:(1)域名(domain identifier);(2)节点(node identifier);(3)源(resource identifier).它的格式是node@domain/resource,node@domain,类似电子邮件的地址格式.domain用来表示接点不同的设备或位置,这个是可选的,例如a在Server1上注册了一个用户,用户名为doom,那么a的JID就是doom@serverl,在发送消息时,指明doom@serverl就可以了,resource可以不用指定,但a在登录到这个Server时,fl的JID可能是doom@serverl、exodus(如果a用Exodus软件登录),也可能是doom@serverl/psi(如果a用psi软件登录).资源只用来识别属于用户的位置或设备等,一个用户可以同时以多种资源与同一个XMPP服务器连接。
- XMPP的XML流
即时通讯的聊天是指上就是二进制流或者字符流。在以前这些命令要么用2进制的形式发送(比如QQ),要么用纯文本指令加空格加参数加换行苻的方式发送(比如MSN)。而XMPP传输的即时通讯指令的逻辑与以往相仿,只是协议的形式变成了XML格式的纯文本。这不但使得解析容易了,人也容易阅读了,方便了开发和查错。而XMPP的核心部分就是一个在网络上分片断发送XML的流协议。这个流协议是XMPP的即时通讯指令的传递基础,也是一个非常重要的可以被进一步利用的网络基础协议。所以可以说,XMPP用TCP传的是XML流。
举个例子看看所谓的XML流是什么样子的?
客户端:<?xmlversion='1.0'?>
<stream:stream
to='example.com'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
version='1.0'>
服务器:<?xmlversion='1.0'?>
<stream:stream
from='example.com'
id='someid'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
version='1.0'>
...其他通信...
客户端:<messagefrom='[email protected]'
to='[email protected]'
xml:lang='en'>
客户端:<body>ArtthounotRomeo,andaMontague?</body>
客户端:</message>
服务器:<messagefrom='[email protected]'
to='[email protected]'
xml:lang='en'>
服务器:<body>Neither,fairsaint,ifeithertheedislike.</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连接。- XML节
XML节通过XML流来发送,XMPP定义了三种顶级XML节
- <iq />
- <message />
- <presence />
XMPP给这三种节定义了五种通用属性
- to
- from
- id
- type
- xml:lang
to属性指定接收节的JID。
from属性指定发送者的JID。
id属性是可选的。并且,在接收应用(通常是一个服务器)中是唯一的。注意:流ID可能是严格安全的,并且因此必须是即不能预测也不能重复的
type属性指定目的或消息上下文,出席或IQ节的详细信息。iq节的type属性有:Error,Get,Result,Set;presence节的type属性有:Available,Subscribe,Subscribed,Unsubscribe,Unsubscribed,Unavailable,Probe,Error,Invisible;message节的type属性有:Chat,Error,GroupChat,Headline,Normal
xml:lang属性值指定任意可读XML字符数据的缺省语言
<message/>节定义了消息语义,<message/>节可被看作“推”机制,一个实体推信息给其它实体,与EMAIL系统中发生的通信类似。所有消息节应该拥有‘to’属性,指定有意的消息接收者;根据接收到那样的一个节,服务器应该路由或传送它到有意的接收者。
<presence/>节定义了出席语义,<presence/>节可被看作基本广播或“出版-订阅”机制,多实体收到他们已订阅(在这种情况下,网络可利用信息)实体的信息。总的来说,出版实体应该发送一个不带‘to’属性的出席节,在这种情况下,与此实体相连的服务器应该广播给所有订阅实体。然而,一个出版实体也可能发送一个带有‘to’属性的出席节,此种情况下,服务器应该路由或传送节到有意的接收者。
<iq />节定义了请求语义,<iq />节可被看作一个请求-响应机制,与[HTTP]在某些方面相似。IQ语义让一个实体向其它实体请求或接收其它实体的响应成为可能。请求与响应的数据内容由IQ无素的直接子元素的命名空间声明定义,并且,交互由请求实体通过使用‘id’属性来跟踪。因此,IQ交互遵从结构化数据交换的一个通用模式,此交换例如得到/结果或设置/结果(虽然如果合适的话,对一个请求的响应可能会以错误返回)。在了解了XMPP的基本结构和一些概念之后,我们暂时告别枯燥的理论学习,来动手搭建一下Openfire+Spark的开发环境,实际感受一下搭建整套IM通讯系统的过程。
- 开发环境:windows XP sp3,Eclipse3.6.1,jdk1.6.0_24,Ant1.7
- 首先从官网上下载最新版本的openfire源码
- 第二步,在Eclipse中创建名为openfire的java项目
- 将openfire源码中openfire_src下的所有文件复制到此项目中,效果如下
- 项目有错误是因为jar包没有加进来,右键点击项目选择Properties,添加build/lib下所有的jar包
- 为了方便编辑,我们要把各个插件的源代码抽出来,在Properties文件夹中选择Source,Add Folders,把src/java和plugins下面的所有插件前边打上勾。
- 效果如下
- 下一步,复制src/i18n/openfire_i18n_en.properties和src/resources/jar/admin-sidebar.xml两个文件,到项目下的bin目录。
- 然后,我们用ant来编译整个项目,选择项目下的build/build.xml文件,运行,若是出现BUILD SUCCESSFUL则编译成功,不行就多来几遍。
- 下面建立项目builder,选择src/java/org/jivesoftware/openfire/starter/ServerStarter.java,右击run as>run configurations,在出现的对话框中选择java application>Arguments,在VM Arguments中输入-DopenfireHome="${workspace_loc:openfire}/target/openfire" ,注意这里的openfire相当于我们的项目名,大小写要注意。再选择Classpth>User Entries,然后点击Advanced>Add Folders,选取项目下的resource文件和src/i18n文件添加进来
- 至此,项目建构完毕,运行ServerStarter.java,会出现以下提示。
<!--192.168.1.237 2012-7-26 10:29:57-->