XMPP(Extensible Messageing and Presence Protocol:可扩展消息与存在协议)RFC3920html
XMPP没有指定任何特定的网络结构,但它一般是采用客户-服务器 架构进行实现,其中客户端经过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通讯。
如下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通信, "=" 表示可以使用任何协议通信)。node
符号的含义以下:
C1, C2, C3 = XMPP 客户端
S1, S2 = XMPP 服务器
G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关
FN1 = 一个外部消息网络
FC1 = 外部消息网络上的一个客户端bash
jid = [ node "@" ] domain [ "/" resource ] domain = fqdn / address-literal fqdn = (sub-domain 1*("." sub-domain)) sub-domain = (internationalized domain label) address-literal = IPv4address / IPv6address e.g.: username@mwee.cn/diancan
tip:一个 JID 的每一个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是总体长度(包括 '@' 和 '/' )不能超过 3071 字节。服务器
<?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> .... </stream:stream> <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> .... </stream:stream>
一个XML流至关于一个会话期间全部XML节的一个信封。咱们能够简单的把它描述成下图:网络
通用属性
如下五种属性通用于 message, presence, 和 IQ 节:架构
<message/>节类型能够被看做是一个"push"机制用于一个实体推送信息给另外一个实体,相似发生在email系统中的通讯. 全部消息节应该处理一个代表预约的消息接收者的'to'属性;接收了这样一个节以后,一个服务器应该路由或递送它给预约的接收者.dom
<presence/> 元素能够被看做一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 一般,一个发行实体应该不带'to'属性发送一个出席信息,这时这个实体所链接的服务器应该广播或复用那个节给全部订阅的实体.不管如何,一个发行实体也能够带'to'属性发送一个出席信息节,这时服务器应该路由或递送这个节给预约的接收者.ui
信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些状况下相似[HTTP].IQ语义学使一个实体可以向另外一个实体作出请求并作出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 而且由请求实体用'id'属性来跟踪这一交互行为. 于是,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):spa
"C"表示从客户端发给服务器,"S"表示从服务器发给客户端.net
C: <?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> S: <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> ... encryption, authentication, and resource binding ... C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'> <body>Art thou not Romeo, and a Montague?</body> </message> S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'> <body>Neither, fair saint, if either thee dislike.</body> </message> C: </stream:stream> S: </stream:stream>
客户端-服务器
如下例子展现一个客户端使用STARTTLS保护数据流
1: 客户端初始化流给服务器: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'> 2: 服务器发送一个流标签给客户端做为应答: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'> 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其余流特性): <stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features> 4: 客户端发送 STARTTLS 命令给服务器: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> 5: 服务器通知客户端能够继续进行: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP链接: <failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> </stream:stream> 6: 客户端和服务器尝试经过已有的TCP链接完成 TLS 握手. 7: 若是 TLS 握手成功, 客户端初始化一个新的流给服务器: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'> (或者): 若是 TLS 握手不成功, 服务器关闭 TCP 链接. 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> <mechanism>EXTERNAL</mechanism> </mechanisms> </stream:features> 9: 客户端继续 SASL 握手
...