[Openfire]使用WebSocket创建Openfire的客户端

  近日工做闲暇之余,对IM系统产生了兴趣,转而研究了IM的内容。找了半天,知道比较流行的是Openfire的系统,Openfire有许多平台实现,因为我是作Web的,因此固然是但愿寻找Web的实现。Openfire的之前的Web实现,是基于Http-bind的一种长轮询机制,固然也没什么很差,只是我如今HTML5都开始了,固然但愿可以来个基于Websocket的机制了。然而Google&百度了很久,也没有找到什么教程,发现这个东西并非很火热的样子,那只好本身开始研究了。因而有了这一篇文章。java

  对了,我知道xmpp的JS框架有几个,但那些框架彷佛都是按照本来的长轮询的机制来作的,并非使用Websocket来作的。程序员

  另外,作软件2年了,当我刚涉足这个行业时,我被告知:“不要重复造轮子!”,曾经我对此深信不疑,但这两年的工做让我愈加认识,不要重复造轮子,仅仅是在于作项目当中,作一个商业产品的时候,考虑到开发速度和产品后期的稳定性及维护性,确实须要采用成熟的技术,但!这不表明做为一个程序员,不该该抱着一种从0开始的研究精神,若是真的热爱这个行业,这个领域,就应该尝试着,根据RCF文档协议,从基础协议的层次开始作软件。web

    好了,废话很少说。恩,开始正文吧。chrome

So 得先搞一个服务端是吧?


 

  确定是去 Openfire 的官网下载最新的Openfire服务端程序啦,Openfire的是开源的,能够免费下载。如图:后端

  1. Openfire 的主程序,主程序是服务端程序,这个主程序不是一个框架,不是一个半成品,而是一个很完整的项目,怎么个很完整?就是你下载下来,直接双击运行(Windows),或到其程序的根目录下bin文件夹,而后执行 openfire start 命令(Linux),Mac就更简单了,直接在“设置”当中会有一个专门的管理窗口。而后它有一个Web版的管理后台,全部设置均可以在这个后台完成,包括安装插件之类的。
  2. 这个火花(Spark)是Openfire搭配的客户端,也是多平台支持的。
  3. 这个地方能够下载Openfire的源代码,你能够把他放到你的IDE中,而后简单配置一下,就能够run起来,这个教程网上不少,我就很少废话了。

  

 安装WebSocket插件


   

  这就不说了。浏览器

创建Websocket链接


 

  安装了WebSocket插件以后,有两个本来用于http-bind的端口,就被WebSocket占用了(有了WebSocket,还须要Http-bind作啥= =)。这两个接口分别是7443和7070,前者是用于HTTPS安全链接,后者是非安全链接。安全

  创建连接:服务器

 1   var connectionState = ["正在链接..", "链接已创建", "正在关闭..", "已经关闭"];
 2     var host = "ws://127.0.0.1:7070/ws/";
 3     if (window.WebSocket != 'undefined') {
 4         //OpenFire是实现了WebSocket的子协议
 5         var connection = new WebSocket(host, "xmpp");
 6         console.log(connectionState[connection.readyState]);
 7         //注册链接创建时的方法
 8         connection.onopen = wsOpen;
 9         //注册链接关闭时的方法
10         connection.onclose = wsClose;
11         //注册收到消息时的方法
12         connection.onmessage = wsMsg;
13     }

  若是要使用Https加密信道,就把Host改为:websocket

var host="wss://127.0.0.1:7443/ws/

  恩,创建安全链接还须要添加安全证书到Keystore,这个在Openfire的根目录下,有一个resource/security文件夹,里面有keyStore文件,固然,这部分我还不是很懂,关于Https的加密信道,TSL/SSl证书的概念,还没彻底弄明白,不过这也不是这篇文章的重点。暂时我就先用非加密的方式来作,至于加密的链接,除了host的区别,其余也没有区别。session

  当Websocket握手以后,咱们要作的第一件事,就是发起一个创建流的请求,

1 function wsOpen(event) {
2         //打印连接状态
3         console.log(connectionState[connection.readyState]);
4         //发送创建流请求
5         var steam = "<open to='127.0.0.1' from='wuxinzhe@127.0.0.1'  xmlns='urn:ietf:params:xml:ns:xmpp-framing' xml:lang='zh' version='1.0'/>";
6         connection.send(steam);
7     }

 

  Websocket下,创建流不像其余平台那样,使用<stream:stream/>标签,而是使用<open/>标签,其中to属性是域名,from是你的JID。

  发出请求以后,会马上收到服务器的响应:

  第一条响应式服务器赞成创建流,第二条是告诉你,安全验证的几种方式,其中最简单的方式是PLAIN方式,这种方式仅仅是将你的帐号密码进行BASE64加密后传输,能够说是很不安全。固然,你也能够选择SCRAM-SHA-1的安全加密方式,只不过你的js库要支持SHA-1加密,我由于是刚开始探路,因此一切从简,SHA-1的加密方式请求流程跟PLAIN会有一点区别,回头我们再说。

  另外我这边写了一个当收到来自服务端信息的方法:

  function wsMsg(event) {
        console.log("Server: " + event.data);
    }

 

  打印出来而已。就像上面console面板中的信息同样。那个是chrome的调试器,其余浏览器也有对应的。

 

发起登陆验证


 

  刚才说了,我先用最基本的PLAIN的方式登陆:

   function auth() {
        //Base64编码
        var token = window.btoa("wuxinzhe@127.0.0.1\0wuxinzhe");
        var message = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" + token + "</auth>";
        console.log("Client: " + message);
        connection.send(message);
    }

 

 

  其中,window.btoa()是自带的方法,不须要额外加载任何库,因此我才说这个真的是最快最简单的方法,而后咱们看方法体内的字符串,这个字符串格式是:jid+password,以\0做为分隔符,后端java程序是一个DefaultAuthProvider提供验证的,固然大家也能够实现本身的验证方式,默认的方式是以\0做为分隔符,注意的是,我一开始密码是123456,发现\0123456这样到后端密码会被分割成23456,\01整个会被转译,恩,解决的办法要嘛就换一个分隔符(我是说后端的openfire那边),要嘛就禁止以数字开头的密码。

  发起安全验证以后,会受到服务端的响应, 若是成功了,如图:  

  至于要是失败了,会返回这个错误,固然这个错误信息不多,究竟是用户名找不到,仍是密码错误了,单凭这个错误信息是看不出来的,不过也没办法咯,要不,去修改一下服务端呗:

 

  当咱们发起安全验证成功了之后,紧接着就要开启一个新的流,新的流服务端会给予一些新的XML节点权限(<iq/>、<presence/>),这样才能发送一些其余功能的信息,好比发送消息,获取联系人列表,再刚开始创建的第一个流失不能发送这些节点的。

  创建新流一样适用<open/>标签,但有一个地方与以前不一样,就是此次是须要携带id属性的,什么是id属性?咱们回顾第一个流创建时,服务端返回的<open/>信息,是否是就有一个id,没错,这个id据个人理解,每次创建websocket链接时,都会为每一个链接生成一个独一无二的id,这个id表明了这个链接,因此后续咱们会在不少不少地方都须要使用这个id。

  发起新的流:

1 <open xmlns='jabber:client' to='127.0.0.1' version='1.0' from='wuxinzhe@127.0.0.1' id='70tvu3ooiu' xml:lang='zh'/>

  服务端会返回两条信息,第一条,是赞成打开新流,第二条,是告诉你,接下来要作的是bind操做,就是要绑定客户端:

  发起绑定也要用到刚才说的id属性:

<iq type='set' id='6ps7q3ideb'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>

  绑定的时候,还能够加入一些标签,来对当前的客户端,作一些比较具备语义的说明,用来描述你的客户端类型:

<iq id="wSBRk-4" type="set">  
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">  
<resource>Showings</resource>  
</bind>  
</iq> 

 

  咱们看看这两种bind之间的区别:

  这是bind的客户端请求内容和服务端响应内容,上面的是没有加入<resource/>标签的,下面是加入了之后。咱们能够看到,服务端返回信息中的<jid/>是有区别的,当不加描述节点的时候,是将前面的id属性直接用做后缀拼接如JID的,加入了之后天然会更具语义化。

  这个过程彷佛是Openfire用于区分登陆的客户端类型的方式。这样若是同一个帐号,在不一样的客户端登陆,也会有所区别。  

  而后咱们要获取session。

<iq xmlns="jabber:client" id="ak014gz6x7" type="set"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>

  这部分我暂时还不知道用来干吗的,毕竟我还没熟悉openfire的xmpp协议的整个过程,因此有些部分不是很清楚,待我整个看过之后,到时候再来看看这个步骤是作什么用的。

  此时咱们进入Openfire的后台,看看用户在线的状况:

  诶?怎么有链接,倒是离线呢?不着急,由于咱们虽然登录了,可是咱们尚未“出席”。就像QQ你能够设置不一样的登陆状态,有在线、不在电脑、忙、离线,这些状态,因此咱们若是要在线,只须要发送出席请求就好了:

<presence id="ak014gz6x7"><status>Online</status><priority>1</priority></presence>

  大家看,处处都要用到这个ID,固然,前面咱们作了绑定动做,此刻不用id属性,换成from="jid"应该也是有效的。

  此时咱们再看后台状态:

  OK了。

  So咱们还要下线呢,关闭链接,此时要用<open/>对应的标签<close/>

<close xmlns="urn:ietf:params:xml:ns:xmpp-framing"/>

  这样就好了。

    其实使用Websocket创建链接与XMPP协议在其余的客户端里是没有什么太大的区别,可能就是<open/><close/>这两个标签的区别。咱们如今可以顺利登陆了,基本上,就是有一个好的开始了。

相关文章
相关标签/搜索