Jabberd/XMPP 学习之八:客户端-服务器示例
来源:互联网 发布:fm2017随机人头像优化 编辑:程序博客网 时间:2024/05/25 23:27
以下例子展示客户端和服务器协商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
第一步: 客户端初始化流到服务器:
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'>
第二步: 服务器发送一个应答流头给客户端来应答:
S: <stream:stream from='im.example.com' id='t7AMCin9zjMNwQKDnplntZPIDEI=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
第三步: 服务器发送流特性给客户端(在这个点上只有STARTTLS扩展, 它是强制协商的):
S: <stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> </stream:features>
第四步: 客户端发送STARTTLS命令给服务器:
C: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
第五步: 服务器通知客户端允许继续:
S: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
第五步(替代): 服务器通知客户端STARTTLS协商失败, 关闭XML流, 并中止TCP连接(所以, 流协商处理以不成功而结束并且双方不再进入下一步):
S: <failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> </stream:stream>
第六步: 客户端和服务器尝试通过现有的TCP连接完成TLS协商(详见TLS).
第七步: 如果TLS协商成功, 客户端通过TLS保护的TCP连接初始化一个新的流到服务器:
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'>
第七步(替代): 如果TLS协商不成功, 服务器关闭TCP连接(所以, 流协商处理以不成功而结束并且双方不再进入下一步):
SASL
第八步: 服务器发送流头给客户端并带上任何可用的流特性来应答:
S: <stream:stream from='im.example.com' id='vgKi/bkYME8OAj4rlXMkpucAqe4=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> S: <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>SCRAM-SHA-1-PLUS</mechanism> <mechanism>SCRAM-SHA-1</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features>
第九步: 客户端选择一个验证机制(在这个场景中, 是 SCRAM-SHA-1), 包含初始化应答数据:
C: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="SCRAM-SHA-1"> biwsbj1qdWxpZXQscj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQQ== </auth>
解码之后的 base 64 数据是 "n,,n=juliet,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AA".
第十步: 服务器发送挑战:
S: <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> cj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQWUxMjQ2OTViLTY5Y TktNGRlNi05YzMwLWI1MWIzODA4YzU5ZSxzPU5qaGtZVE0wTURndE5HWTBaaT AwTmpkbUxUa3hNbVV0TkRsbU5UTm1ORE5rTURNeixpPTQwOTY= </challenge>
解码后的 base 64 数据是 "r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de6-9c30-b51b3808c59e,s=NjhkYTM0MDgtNGY0Zi00NjdmLTkxMmUtNDlmNTNmNDNkMDMz,i=4096" (实际数据中是没有换行的).
第十一步: 客户端发送一个应答:
C: <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> Yz1iaXdzLHI9b01zVEFBd0FBQUFNQUFBQU5QMFRBQUFBQUFCUFUwQUFlMTI0N jk1Yi02OWE5LTRkZTYtOWMzMC1iNTFiMzgwOGM1OWUscD1VQTU3dE0vU3ZwQV RCa0gyRlhzMFdEWHZKWXc9 </response>
解码后的 base 64 数据是 "c=biws,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0 AAe124695b-69a9-4de6-9c30-b51b3808c59e,p=UA57tM/ SvpATBkH2FXs0WDXvJYw=" (实际数据中是没有换行的).
第十二步: 服务器通知客户端成功了, 并且包含了额外的数据:
S: <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289 </success>
解码后的 base 64 数据是 "v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo=".
第十二步(替代): 服务器返回一个SASL错误给客户端(所以, 流协商处理以不成功结束并且双方不再进行下一步):
S: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <not-authorized/> </failure> </stream>
第十三步: 客户端初始化一个新的流到服务器:
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'>
资源绑定
第十四步: 服务器发送一个流头到客户端并带上支持的特性(在这个场景中, 是资源绑定)来应答:
S: <stream:stream from='im.example.com' id='gPybzaOzBmaADgxKXu9UClbprp0=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> S: <stream:features> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> </stream:features>
在被通知资源绑定是强制协商之后, 客户端需要绑定一个资源到流; 这里我们假定客户端提交了一个自然人可读的文本字符串.
第十五步: 客户端绑定一个资源:
C: <iq id='yhc13a95' type='set'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <resource>balcony</resource> </bind> </iq>
第十六步: 服务器接受提交的资源部分并通知客户端资源绑定成功:
S: <iq id='yhc13a95' type='result'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <jid> juliet@im.example.com/balcony </jid> </bind> </iq>
第十六步(替代): 服务器返回错误给客户端(所以, 流协商处理以不成功结束并且双方不再进入下一步):
S: <iq id='yhc13a95' type='error'> <error type='cancel'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
节交换
现在客户端被允许通过协商好的流发送XML节了.
C: <message from='juliet@im.example.com/balcony' id='ju2ba41c' to='romeo@example.net' type='chat' xml:lang='en'> <body>Art thou not Romeo, and a Montague?</body> </message>
如果必要, 发送者的服务器和预定的接收者的服务器协商XML流(见9.2).
预定的接收者应答, 并且消息被递送到客户端.
E: <message from='romeo@example.net/orchard' id='ju2ba41c' to='juliet@im.example.com/balcony' type='chat' xml:lang='en'> <body>Neither, fair saint, if either thee dislike.</body> </message>
客户端随后可以通过这个流继续发送和接收不限数量的XML节.
关闭
不想发送更多的消息, 客户端关闭它到服务器的流,不在等待来自服务器的入站数据了.
C: </stream:stream>
和4.4一致, 服务器可能发送额外的数据给客户端然后才关闭到该客户端的流.
S: </stream:stream>
客户端现在发送一个 TLS close_notify 警告, 从服务器接收到一个 close_notify 警告应答, 然后中止当前的TCP连接.
转自:http://wiki.jabbercn.org/RFC6120
- Jabberd/XMPP 学习之八:客户端-服务器示例
- Jabberd/XMPP 学习之九:服务器-服务器示例
- Jabberd/XMPP 学习之六:jabberd服务器安装
- Jabberd/XMPP 学习之二:jabberd的默认安装位置
- Jabberd/XMPP 学习之四:服务器处理XML节的规则
- Jabberd/XMPP 学习之五:常用名字空间
- Jabberd/XMPP 学习之七:xml流和xml节
- Jabberd/XMPP 学习之一:概述
- Jabberd/XMPP 学习之三:jabber/xmpp中to,from、message,id,type,xml:lang的使用
- ejabberd、jabber、jabberd、xmpp辨析
- ejabberd、jabber、jabberd、xmpp辨析
- ejabberd、jabber、jabberd、xmpp辨析
- iOS 开发 XMPP即时通讯项目开发(仿微信)-详解之xmpp环境搭建(数据库/客户端/服务器)
- iOS 开发 XMPP即时通讯项目开发(仿微信)-详解之xmpp环境搭建(数据库/客户端/服务器)
- xmpp客户端,服务器搭建要点
- STL学习之八:priority_queue用法示例
- 基于XMPP的JABBERD功能特性分析
- XMPP客户端库Smack 4.1.4版官方开发文档之八
- 人是能接受暗示的动物,和积极的人在一起吧
- HDU-1710 Binary Tree Traversals 二叉树遍历
- 三部排序
- 自己写的lua测试
- Hadoop MapReduce进阶 使用分布式缓存进行replicated join
- Jabberd/XMPP 学习之八:客户端-服务器示例
- 我的VIM配置文件 vimrc (for c/c++)
- ios 开发随记 SDWebImage
- hfdjgkuyjoliugfdgsg
- 打印螺旋数组
- Android的CursorLoader用法小结(Loader的间接子类)
- 时间类
- 使用js实现按钮的滑动效果
- ImageMagick +Jmagick安装