以下例子展示客户端和服务器协商XML流,交换XML节,和关闭已协商的流的XMPP数据流. 服务器是"im.example.com",该服务器要求使用TLS,客户端验证使用SASL SCRAM-SHA-1机制,客户端帐号是<juliet@im.example.com>而密码是"r0m30myr0m30",并且客户端在这个流上提交了一个资源绑定请求. 我们假设在发送初始化流头之前,客户端已经解析了_xmpp‑client._tcp.im.example.com的SRV记录并已经打开一个TCP连接到已解析的IP地址和声明的端口上.
TLS
第一步: 客户端初始化流到服务器:
@H_301_18@C: <stream:stream
from='juliet@im.example.com'
to='im.example.com'
version='1.0'
xml:lang='en'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'>
第二步: 服务器发送一个应答流头给客户端来应答:
@H_301_18@S: <stream:stream
id=
't7AMCin9zjMNwQKDnplntZPIDEI='
'http://etherx.jabber.org/streams'>
第三步: 服务器发送流特性给客户端(在这个点上只有STARTTLS扩展,它是强制协商的):
@H_301_18@S: <stream:features>
<starttls 'urn:ietf:params:xml:ns:xmpp-tls'>
<required/>
</starttls>
</stream:features>
第四步: 客户端发送STARTTLS命令给服务器:
@H_301_18@C: <starttls 'urn:ietf:params:xml:ns:xmpp-tls'/>
第五步: 服务器通知客户端允许继续:
@H_301_18@S: <proceed 'urn:ietf:params:xml:ns:xmpp-tls'/>
第五步(替代): 服务器通知客户端STARTTLS协商失败,关闭XML流,并中止TCP连接(所以,流协商处理以不成功而结束并且双方不再进入下一步):
@H_301_18@S: <failure 'urn:ietf:params:xml:ns:xmpp-tls'/>
</stream:stream>
第六步: 客户端和服务器尝试通过现有的TCP连接完成TLS协商(详见TLS).
第七步: 如果TLS协商成功,客户端通过TLS保护的TCP连接初始化一个新的流到服务器:
'http://etherx.jabber.org/streams'>
第七步(替代): 如果TLS协商不成功,服务器关闭TCP连接(所以,流协商处理以不成功而结束并且双方不再进入下一步):
SASL
第八步: 服务器发送流头给客户端并带上任何可用的流特性来应答:
'vgKi/bkYME8OAj4rlXMkpucAqe4='
'http://etherx.jabber.org/streams'>@H_
301_18@ S:
<stream:features>
<mechanisms 'urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>@H_
301_18@SCRAM-SHA-1-PLUS
</mechanism>
<mechanism>@H_
301_18@SCRAM-SHA-1
</mechanism>
<mechanism>@H_
301_18@PLAIN
</mechanism>
</mechanisms>
</stream:features>
第九步: 客户端选择一个验证机制(在这个场景中,是 SCRAM-SHA-1),包含初始化应答数据:
@H_301_18@C: <auth "urn:ietf:params:xml:ns:xmpp-sasl"
mechanism=
"SCRAM-SHA-1">@H_
301_18@ biwsbj1qdWxpZXQscj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQQ==
</auth>
解码之后的 base 64 数据是 "n,n=juliet,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AA".
第十步: 服务器发送挑战:
@H_301_18@S: <challenge "urn:ietf:params:xml:ns:xmpp-sasl">@H_
301_18@ cj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQWUxMjQ2OTViLTY5Y TktNGRlNi05YzMwLWI1MWIzODA4YzU5ZSxzPU5qaGtZVE0wTURndE5HWTBaaT AwTmpkbUxUa3hNbVV0TkRsbU5UTm1ORE5rTURNeixpPTQwOTY=
</challenge>
解码后的 base 64 数据是 "r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de6-9c30-b51b3808c59e,s=NjhkYTM0MDgtNGY0Zi00NjdmLTkxMmUtNDlmNTNmNDNkMDMz,i=4096" (实际数据中是没有换行的).
第十一步: 客户端发送一个应答:
@H_301_18@C: <response "urn:ietf:params:xml:ns:xmpp-sasl">@H_
301_18@ Yz1iaXdzLHI9b01zVEFBd0FBQUFNQUFBQU5QMFRBQUFBQUFCUFUwQUFlMTI0N jk1Yi02OWE5LTRkZTYtOWMzMC1iNTFiMzgwOGM1OWUscD1VQTU3dE0vU3ZwQV RCa0gyRlhzMFdEWHZKWXc9
</response>
解码后的 base 64 数据是 "c=biws,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0 AAe124695b-69a9-4de6-9c30-b51b3808c59e,p=UA57tM/ SvpATBkH2FXs0WDXvJYw=" (实际数据中是没有换行的).
第十二步: 服务器通知客户端成功了,并且包含了额外的数据:
@H_301_18@S: <success 'urn:ietf:params:xml:ns:xmpp-sasl'>@H_
301_18@ dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289
</success>
解码后的 base 64 数据是 "v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo=".
第十二步(替代): 服务器返回一个SASL错误给客户端(所以,流协商处理以不成功结束并且双方不再进行下一步):
'urn:ietf:params:xml:ns:xmpp-sasl'>
<not-authorized/>
</failure>
</stream>
第十三步: 客户端初始化一个新的流到服务器:
'http://etherx.jabber.org/streams'>
资源绑定
第十四步: 服务器发送一个流头到客户端并带上支持的特性(在这个场景中,是资源绑定)来应答:
'gPybzaOzBmaADgxKXu9UClbprp0='
'http://etherx.jabber.org/streams'>@H_
301_18@ S:
<stream:features>
<bind 'urn:ietf:params:xml:ns:xmpp-bind'/>
</stream:features>
在被通知资源绑定是强制协商之后,客户端需要绑定一个资源到流; 这里我们假定客户端提交了一个自然人可读的文本字符串.
第十五步: 客户端绑定一个资源:
@H_301_18@C: <iq 'yhc13a95' type=
'set'>
<bind 'urn:ietf:params:xml:ns:xmpp-bind'>
<resource>@H_
301_18@balcony
</resource>
</bind>
</iq>
第十六步: 服务器接受提交的资源部分并通知客户端资源绑定成功:
@H_301_18@S: <iq 'result'>
<bind 'urn:ietf:params:xml:ns:xmpp-bind'>
<jid>@H_
301_18@ juliet@im.example.com/balcony
</jid>
</bind>
</iq>
第十六步(替代): 服务器返回错误给客户端(所以,流协商处理以不成功结束并且双方不再进入下一步):
'error'>
<error 'cancel'>
<conflict 'urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
节交换
现在客户端被允许通过协商好的流发送XML节了.
@H_301_18@C: <message 'juliet@im.example.com/balcony'
'ju2ba41c'
'romeo@example.net'
'chat'
'en'>
<body>@H_
301_18@Art thou not Romeo,and a Montague?
</body>
</message>
如果必要,发送者的服务器和预定的接收者的服务器协商XML流(见@L_301_1@).
预定的接收者应答,并且消息被递送到客户端.
@H_301_18@E: <message 'romeo@example.net/orchard'
'en'>
<body>@H_
301_18@Neither,fair saint,if either thee dislike.
</body>
</message>
客户端随后可以通过这个流继续发送和接收不限数量的XML节.
不想发送更多的消息,客户端关闭它到服务器的流,不在等待来自服务器的入站数据了.
@H_301_18@C: </stream:stream>
和4.4一致,服务器可能发送额外的数据给客户端然后才关闭到该客户端的流.
@H_301_18@S: </stream:stream>
客户端现在发送一个 TLS close_notify 警告,从服务器接收到一个 close_notify 警告应答,然后中止当前的TCP连接.
转自:http://wiki.jabbercn.org/RFC6120