分享

使用Strophe连接xmpp,轻松构建web即时聊天工具

 WindySky 2016-06-30

使用Strophe连接xmpp,轻松构建web即时聊天工具。

实现原理
实现webim方法有很多,最关键的问题是保持和服务端的连接。如何保障会话的即时性和连通性。常用的有poll, long poll,  comet等;; 其中poll的方式效果最差,一般都会有1到2秒的延迟。long poll和comet技术比较新,因为http无状态的原因,这种长连接方式要保持,一般都需要服务端额外代码提供支持。像gtalk采用的就是long poll的方式。服务端常会使用异步IO等方式来支持高并发。
本文使用的是XEP标准扩展规范,XEP-0124 提供的方法实现WebIM. 思路即使用一个javascript的xep-0124的实现,直接连接xmpp server端。目前xep-0124的实现,在大部分的xmpp server实现中都支持,本文使用的是OpenFire 3.6.4 作为Xmpp Server。
XEP 0124规范定义了一个比较完整和安全的协议,具体请参阅相当文档。本文使用javascript端的XEP-0124的实现为Strophe的js实现。
另外因为浏览器javascript跨域问题,需要使webim里调用javascript也是80端口,并同一子域,所以使用Apache或者Nginx 在80端口,并转发/http-bind请求至Xmpp Server的http-binding端口。本机使用Nginx. xmpp server 使用使用7070端口。

一、安装openfire:http://blog.csdn.net/e421083458/article/details/38037373

二、配置apache


    我们下载安装的是httpd-2.2.17-win32-x86-no_ssl.msi,安装完成后,我们需要配置一下,由于jwchat是用javacript去和openfire进行通讯的,所以他们之间的通讯是基于http的,但是由于浏览器为了安全性是不允许javascript跨域访问的。我们必须通过别的技术来绕过这限制,所以我们采取apache服务器的重定向功能去突破这个限制。

     安装完成后进入到apache的安装目找到conf文件夹下的httpd.conf文件,用记事本打开,把下列几个配置项放开(默认被注释掉了)

1、LoadModule rewrite_module modules/mod_rewrite.so
2、LoadModule proxy_module modules/mod_proxy.so
3、LoadModule proxy_http_module modules/mod_proxy_http.so

然后再在本配置文件的末尾加入如下几行配置

  ServerName
  <Directory /var/jwchat>
    Options  +Indexes +MultiViews
  </Directory>
  AddDefaultCharset UTF-8
  RewriteEngine on
  ProxyPass /jwchat/http-bind/ http://:7070/http-bind/   

在此有必要对proxyPass的参数做些说明

“/jwchat/http-bind/”:jwchat就通过访问http://域名/jwchat/http-bind/地址去和openfire通讯,apache接到请求后就会重新定向到http://:7070/http-bind/

“http://:7070/http-bind/”:被重新定向的地址,也就是我们的openfire的http访问地址。7070端口是openfire的默认访问端口,当然我们也可以进入openfire进行配置。

三、openfire的配置
安装好openfire后进入web式的管理界面,选择服务器-》服务器管理器-》系统属性
在里边添加两个属性(记得选择不加密)
xmpp.httpbind.client.requests.polling = 0
xmpp.httpbind.client.requests.wait = 10


四、创建聊天脚本

创建index.html页面:

  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <title>Latest content</title>  
  5.         <script type="text/javascript" src="http://ajax./ajax/libs/jquery/1.7.2/jquery.min.js"></script>  
  6.         <script type="text/javascript"    
  7. src="strophejs/strophe.js"></script>  
  8.         <script type="text/javascript"   
  9. src="pingstream.js"></script>  
  10.     </head>  
  11.     <body>  
  12.       <div id='login' style='text-align: left'>  
  13.         <form name='cred'>  
  14.           <label for='jid'>JID:</label>  
  15.           <input type='text' id='jid' value="richard@csdn.shimiso.com" /><br/>  
  16.           <label for='pass'>Password:</label>  
  17.           <input type='password' id='pass' value="niuyufu123" /><br/>  
  18.           <input type='button' id='connect' value='connect' />  
  19.         </form>  
  20.       </div>  
  21.       <hr />  
  22.       <div style="text-align: left">  
  23.           <label for='tojid'>tojid</label>  
  24.           <input type='text' id='tojid' value="" /><br/>  
  25.           <label for='msg'>msg:</label>  
  26.           <textarea id="msg">Hello world!!!</textarea>  
  27.           <br/>  
  28.           <input type='button' id='replay' value='replay' />  
  29.       </div>  
  30.       <hr />  
  31.       <div id='log'></div>  
  32.     </body>  
  33. </html>  

创建pingstream.js

[javascript] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. var BOSH_SERVICE = '/http-bind/';  
  2. var connection = null;  
  3.   
  4. function log(msg)   
  5. {  
  6.     $('#log').append('<div></div>').append(document.createTextNode(msg));  
  7. }  
  8.   
  9. /** 
  10.  * 连接绑定方法 
  11.  * @param status 
  12.  */  
  13. function onConnect(status)  
  14. {  
  15.     if (status == Strophe.Status.CONNECTING) {  
  16.     log('Strophe is connecting.');  
  17.     } else if (status == Strophe.Status.CONNFAIL) {  
  18.     log('Strophe failed to connect.');  
  19.     $('#connect').get(0).value = 'connect';  
  20.     } else if (status == Strophe.Status.DISCONNECTING) {  
  21.     log('Strophe is disconnecting.');  
  22.     } else if (status == Strophe.Status.DISCONNECTED) {  
  23.     log('Strophe is disconnected.');  
  24.     $('#connect').get(0).value = 'connect';  
  25.     } else if (status == Strophe.Status.CONNECTED) {  
  26.     log('Strophe is connected.');  
  27.     log('ECHOBOT: Send a message to ' + connection.jid +   
  28.         ' to talk to me.');  
  29.       
  30.     connection.addHandler(onMessage, null, 'message', null, null,  null);   
  31.     connection.send($pres().tree());  
  32.     }  
  33. }  
  34.   
  35. /** 
  36.  * 获取消息时的方法 
  37.  * @param msg 
  38.  * @returns {Boolean} 
  39.  */  
  40. function onMessage(msg) {  
  41.     var to = msg.getAttribute('to');  
  42.     var from = msg.getAttribute('from');  
  43.     var type = msg.getAttribute('type');  
  44.     var elems = msg.getElementsByTagName('body');  
  45.   
  46.     if (type == "chat" && elems.length > 0) {  
  47.     var body = elems[0];  
  48.   
  49.     log('ECHOBOT: I got a message from ' + from + ': ' +   
  50.         Strophe.getText(body));  
  51.       
  52. /*  关闭echo机器的自动回复 
  53.     var reply = $msg({to: from, from: to, type: 'chat'}) 
  54.             .cnode(Strophe.copyElement(body)); 
  55.     connection.send(reply.tree()); 
  56.  
  57.     log('ECHOBOT: I sent ' + from + ': ' + Strophe.getText(body));*/  
  58.       
  59.       
  60.     }  
  61.     return true;  
  62. }  
  63.   
  64. /** 
  65.  * 发信息 
  66.  * @param toId 
  67.  * @param fromId 
  68.  * @param msg 
  69.  */  
  70. function sendMsg(toId,fromId,msg) {  
  71.     var reply = $msg({to: toId, from:fromId , type: 'chat'}).cnode(Strophe.xmlElement('body', '' ,msg));  
  72.     connection.send(reply.tree());  
  73.     log('ECHOBOT: I sent ' + toId + ': ' + msg);  
  74. }  
  75.   
  76. /** 
  77.  * 事件监听 
  78.  */  
  79. $(document).ready(function () {  
  80.     connection = new Strophe.Connection(BOSH_SERVICE);  
  81.   
  82.     // Uncomment the following lines to spy on the wire traffic.  
  83.     connection.rawInput = function (data) { console.log('RECV: ' + data); };  
  84.     connection.rawOutput = function (data) { console.log('SEND: ' + data); };  
  85.   
  86.     // Uncomment the following line to see all the debug output.  
  87.     //Strophe.log = function (level, msg) { log('LOG: ' + msg); };  
  88.   
  89.     $('#connect').bind('click', function () {  
  90.     var button = $('#connect').get(0);  
  91.     if (button.value == 'connect') {  
  92.         button.value = 'disconnect';  
  93.         connection.connect($('#jid').get(0).value,  
  94.                    $('#pass').get(0).value,  
  95.                    onConnect);  
  96.     } else {  
  97.         button.value = 'connect';  
  98.         connection.disconnect();  
  99.     }  
  100.     });  
  101.       
  102.     $('#replay').bind('click', function () {  
  103.         toId = $('#tojid').val();  
  104.         fromId = $('#jid').val();  
  105.         msg=$('#msg').val();  
  106.         sendMsg(toId,fromId,msg);  
  107.     });  
  108. });  

用pandian与聊天页并行测试。

成功后的截图:

代码下载地址:http://download.csdn.net/detail/e421083458/7672297


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多