说起 XMPP,那第一反应就是即时通信。它基于可扩展标记语言(XML)来进行数据交换。
XMPP 中定义了三个角色,客户端,服务器,网关。通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录,连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。基本的网络形式是单客户端通过 TCP/IP 连接到单服务器,然后在之上传输 XML。
<message from="admin@dannysite.com" to="danny@dannysite.com"> <body>Hi, Danny!</body> </message>
这是一段典型的 XMPP 交换数据,正如前面提到的,它是 XML 格式。message 表明这是一条消息,可以理解为 admin@dannysite.com 向 danny@dannysite.com 发送了一句问候“Hi, Danny!”。一切就是这么简单!
XMPP 在客户端与服务器间建立一个基于 TCP 协议的长连接,随后即可进行异步的 XML 数据交换。这是与像 Web 或 Email 技术本质的区别所在,他们仅仅是在需要的时候建立一个连接,完成一个事务,然后关闭连接。这种模式无法实现实时性的交互,因为两者间并没有建立一个持久性的通道来允许服务器实时的将消息推送到客户端。XMPP 则相反,它不仅允许服务器能实时的和客户端沟通,还允许客户端无阻塞地发送多条请求而无需等待先前的回复。服务端只需在完成处理之后动态的将数据推回给客户端即可。
stanza, stanza and stanza
正如你之前看到的,交互的数据载体就是 XML,它作为通讯的基本单元,类似于网络通信中的数据包。或者说称其为 stanza(节点)。stanza 包含以下概念:
• 节点名,包括 message, presence 和 iq,每种节都要各种的作用,客户端也会区别处理;
• 属性,XML 节都有各自的属性,并且这些属性都有重要的意义;
• 子节点,承载的数据,这些承载可能会展示给用户,也可能是承载命名空间下定义的其他行为。让我们来具体看看几种 stanza 类型。
Message
很明显,这是消息的载体。它应用于即时通讯、组消息、提醒和通知等场景中。根据 type 的不同,Message 可以分为五种:
normal:定义独立的消息,它不期待消息的回复;
chat:理解为即时聊天消息即可;
groupchat:用于多用户聊天;
headline:类型的消息用于发送提醒和通知;
error:当双方前面发送的消息处理过程中有错误发生,该类型的节点就用反馈错误信息。
另外 from 和 to 属性则分别代表消息的发送方和接收方。子节点里则承载了消息的主体,如 <body/> 和 <subject/>,下面是一个示例:
<message from="danny@dannysite.com/foo" to="tom@dannysite.com" type="chat"> <body>Who are you?</body> <subject>Query</subject> </message>
Presence
Presence 用于告知他人当前的状态,是上线、还是离线。这样别人就知道你是否在线或者说可否与你回话。
从最基本的来说,presence 本身就像一个开关,应只有在线和离线两种状态。不过这只是理论而已,presence 的状态可以自定义,如设定一个“离开”或者“请勿打扰”。自定义的状态只需放在 status 消息中即可。例如:
<presence from="danny@dannysite.com/pda"> <show>xa</show> <status>down the rabbit hole!</status> </presence>
当然,作为用户来说可不希望无论谁都可以看到自己的在线状态,presence subscription 确保只有授权后的用户才能收到你的 presence 消息。
IQ
IQ,即 Info/Query(信息/查询),它为 XMPP 通信提供请求与响应机制,如同 HTTP 里的GET、POST 或 PUT。不同于 Message 的是,IQ 只能包含一个载体,其为需要处理的请求或回复。每个 IQ 都必须有一个响应,且其中必需的 id 属性将用来把请求和对应的响应关联起来。IQ 有4种,通过该节的 type 属性区分,分别为 get 和 set 两种请求及 result 和 error 两种响应。
假如要查询联系人列表:
C:<iq from="danny@dannysite.com/pda" id="rr82a1z7" to="danny@dannysite.com" type="get"> <query xmlns="jabber:iq:roster"/> </iq> S:<iq from="danny@dannysite.com" id="rr82a1z7" to="danny@dannysite.com/pda" type="result"> <query xmlns="jabber:iq:roster"> <item jid="tom@dannysite.com"/> <item jid="kyle@dannysite.com"/> <item jid="andrew@dannysite.com"/> </query> </iq>
注意其中以“jabber:iq:roster”作为命名空间的 query 载荷,在客户端发出 IQ 时,里面是空的,而服务器返回时则包含多个 <item/> 元素,每个 <item/> 元素都为一个联系人。另外,请求和回送中的 id 一样,从而保证一一对应。
说完一些最基本的东西,接下来则是应用。