该帖子展示了如何安装openfire 以及做一些配置 例如cross-domain 并且会在本地安装spark客户端以及web客户端, web客户端主要用于打印日志,输出客户端与XMPP服务器之间传输XMPP节。 web客户端主要参照了《Professional XMPP Programming with JavaScript and jQuery》这本书 第4章的例子,该书的PDF下载地址:http://ishare.iask.sina.com.cn/f/12563306.html
第一步 下载安装openfire和spark的最新版本 到下面的页面下载即可。注意openfire请下载zip版本。 至于spark就看你的电脑有么有安装jre 如果安装了 就下载 spark_online.exe版本如果没有安装请下载spark.exe版本
http://www.igniterealtime.org/downloads/index.jsp
下载完以后解压缩 然后配置http绑定(这一步很关键 如果配置不正确的话 本地Web客户端无法通过bosh连接 至于bosh是啥玩意你自己到网上找)在openfire目录下的conf目录下建立一个XML文件,取名为crossdomain.xml 并且把以下的XML代码粘上去然后保存
<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <site-control permitted-cross-domain-policies="all"/> <allow-access-from domain="*" to-ports="5222,5223,7070,7443" secure="true"/> </cross-domain-policy>
然后启动,打开cmd进入openfire目录 执行以下命令:
java -Xms512m -Xmx1024m -DopenfireHome=./ -Dopenfire.lib.dir=./lib/ -classpath ./lib/startup.jar -jar ./lib/startup.jar
其中-Xms512m -Xmx1024m这两个参数你自己看着办。
执行完以上命令 openfire就启动了。进入管理页面 首先会让你初始化openfire,例如语言,数据库等 这些初始化设置网上一大片你自己找。
配置完以后通过管理员帐号进入管理页面的服务器设置页面 确保http绑定已经启动了7070端口。OK 完事了。
然后安装spark,这东西没啥可说的 跟安装QQ一样简单 一路下一步即可。安装完以后多建立几个帐号 留给web客户端用。
现在开始搭建web客户端 这东西主要用来输出日志 以及发送xmpp节 让你感受一下以底层的方式通过发送艾克斯艾姆屁屁节与服务器端打交道。至于xmpp节的含义以及使用你到网上找 一大片一大片的。
我用eclipse建立了一个static web程序(下载附件)
以下是web客户端的html文件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Peek - Chapter 4</title> <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/cupertino/jquery-ui.css"> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.js"></script> <!-- strophe是xmpp的客户端 我们是用它来与xmpp通信的 --> <script type="text/javascript" src="../js/strophe.js"></script> <!-- flXHR用来跨域请求 --> <script type="text/javascript" src="../js/flensed/flXHR.js"></script> <!-- strophe的flxhr插件 --> <script type="text/javascript" src="../js/strophe.flxhr.js"></script> <!-- 该页面的css文件 --> <link rel='stylesheet' type='text/css' href='peek.css'> <!-- 针对这个web客户端写的js 里面有很多重要的内容 细看 下面有详细的说明 --> <script src='peek.js'></script> </head> <body> <h1>Peek</h1> <div id='console'></div> <textarea id='input' class='disabled' disabled='disabled'></textarea> <div id='buttonbar'> <input id='send_button' type='button' value='Send Data' disabled='disabled' class='button'> <input id='disconnect_button' type='button' value='Disconnect' disabled='disabled' class='button'> </div> <!-- login dialog --> <div id='login_dialog' class='hidden'> <label>JID:</label><input type='text' id='jid'> <label>Password:</label><input type='password' id='password'> </div> </body> </html>
下面是peek.js文件
// 建立Peek对象 var Peek = { connection: null, // 用来保存Strophe.Connection对象 // show_traffic方法用来打印输出的xmpp节和从xmpp服务器接收到的xmpp节,至于细节可以不看,看了也就那么回事。 // body是输入和输出的xmpp节,type分incoming和outgoing区分输入和输出 以达到以不同的颜色区分输入和输出,黑色背景是我自己发出的输出节 棕色北京是服务器端发来的xmpp节 show_traffic: function (body, type) { if (body.childNodes.length > 0) { var console = $('#console').get(0); var at_bottom = console.scrollTop >= console.scrollHeight - console.clientHeight;; $.each(body.childNodes, function () { // var str = Strophe.serialize(this); // alert(type + ': ' + str); $('#console').append("<div class='" + type + "'>" + Peek.pretty_xml(this) + "</div>"); }); if (at_bottom) { console.scrollTop = console.scrollHeight; } } }, // 该方法用于美化xmpp节 你觉得有用你就自己细看 pretty_xml: function (xml, level) { var i, j; var result = []; if (!level) { level = 0; } result.push("<div class='xml_level" + level + "'>"); result.push("<span class='xml_punc'><</span>"); result.push("<span class='xml_tag'>"); result.push(xml.tagName); result.push("</span>"); // attributes var attrs = xml.attributes; var attr_lead = [] for (i = 0; i < xml.tagName.length + 1; i++) { attr_lead.push(" "); } attr_lead = attr_lead.join(""); for (i = 0; i < attrs.length; i++) { result.push(" <span class='xml_aname'>"); result.push(attrs[i].nodeName); result.push("</span><span class='xml_punc'>='</span>"); result.push("<span class='xml_avalue'>"); result.push(attrs[i].nodeValue); result.push("</span><span class='xml_punc'>'</span>"); if (i !== attrs.length - 1) { result.push("</div><div class='xml_level" + level + "'>"); result.push(attr_lead); } } if (xml.childNodes.length === 0) { result.push("<span class='xml_punc'>/></span></div>"); } else { result.push("<span class='xml_punc'>></span></div>"); // children $.each(xml.childNodes, function () { if (this.nodeType === 1) { result.push(Peek.pretty_xml(this, level + 1)); } else if (this.nodeType === 3) { result.push("<div class='xml_text xml_level" + (level + 1) + "'>"); result.push(this.nodeValue); result.push("</div>"); } }); result.push("<div class='xml xml_level" + level + "'>"); result.push("<span class='xml_punc'></</span>"); result.push("<span class='xml_tag'>"); result.push(xml.tagName); result.push("</span>"); result.push("<span class='xml_punc'>></span></div>"); } return result.join(""); }, // 用来将你输入XMPP节转换成XMP text_to_xml: function (text) { var doc = null; if (window['DOMParser']) { var parser = new DOMParser(); doc = parser.parseFromString(text, 'text/xml'); } else if (window['ActiveXObject']) { var doc = new ActiveXObject("MSXML2.DOMDocument"); doc.async = false; doc.loadXML(text); } else { throw { type: 'PeekError', message: 'No DOMParser object found.' }; } var elem = doc.documentElement; if ($(elem).filter('parsererror').length > 0) { return null; } return elem; } }; $(document).ready(function () { // 登录窗口 $('#login_dialog').dialog({ autoOpen: true, draggable: false, modal: true, title: 'Connect to XMPP', buttons: { "Connect": function () { $(document).trigger('connect', { jid: $('#jid').val(), password: $('#password').val() }); $('#password').val(''); $(this).dialog('close'); } } }); // 断开与xmpp服务器之间的连接的按钮 $('#disconnect_button').click(function () { Peek.connection.disconnect(); }); // 发送你输入的XMPP节的按钮 $('#send_button').click(function () { var input = $('#input').val(); var error = false; if (input.length > 0) { if (input[0] === '<') { var xml = Peek.text_to_xml(input); if (xml) { Peek.connection.send(xml);// 发送你输入的XMPP节到XMPP服务器 $('#input').val(''); } else { error = true; } } else if (input[0] === '$') { // 如果你输入的stophe的代码 那就会实行 但最终还是会生成XML格式的 try { var builder = eval(input); Peek.connection.send(builder); $('#input').val(''); } catch (e) { console.log(e); error = true; } } else { error = true; } } if (error) { $('#input').animate({backgroundColor: "#faa"}); } }); $('#input').keypress(function () { $(this).css({backgroundColor: '#fff'}); }); }); $(document).bind('connect', function (ev, data) { // 千万别忘了改成你自己用openfire安装的xmpp服务器的http绑定地址 var conn = new Strophe.Connection("http://anywhere:7070/http-bind/"); // xmlInput方法用来接收服务器发送来的XMPP节 conn.xmlInput = function (body) { // alert('Input: ' + body); Peek.show_traffic(body, 'incoming'); }; // xmlOutput是客户端发送的xmpp节 conn.xmlOutput = function (body) { // alert('Output: ' + body); Peek.show_traffic(body, 'outgoing'); }; // 连接xmpp服务器 Strophe在连接的过程中有好几个状态 其中包括Strophe.Status.CONNECTED,Strophe.Status.DISCONNECTED等,详细的信息你自己看书查 (第3章 48页) conn.connect(data.jid, data.password, function (status) { if (status === Strophe.Status.CONNECTED) { $(document).trigger('connected'); } else if (status === Strophe.Status.DISCONNECTED) { $(document).trigger('disconnected'); } }); Peek.connection = conn; }); // 绑定已经连接的事件 $(document).bind('connected', function () { $('.button').removeAttr('disabled'); $('#input').removeClass('disabled').removeAttr('disabled'); }); // 绑定断开连接的事件 $(document).bind('disconnected', function () { $('.button').attr('disabled', 'disabled'); $('#input').addClass('disabled').attr('disabled', 'disabled'); });
使用流程 当你打开这个WEB客户端的时候 页面会提示你登录,你就用通过spark建立的账户登录就行,登录完以后控制台会输出一大堆xmpp节 黑色背景的是你自己发送的 棕色北京是服务器发送过来的。
现在你就可以通过这个web客户端与spark客户端进行好友添加 聊天了 例如你添加好友的话就需要订阅这个好友 并且那个好友也需要订阅你 这样你们俩才能进行聊天 参照下面的xmpp节:
<presence /> <!-- 出席可用,相当于QQ里的上线 --> <iq from="seong@anywhere" type="get" id="roster1"> <query xmlns="jabber:iq:roster"/> </iq> <!-- 获取自己的花名册 相当于QQ里的获取好友列表 --> <presence from="aobama@anywhere" to="xijinping@anywhere" type="subscribe"/> <!-- 出席订阅,相当于QQ里的添加好友,在这里是奥巴马添加习大大为好友 --> <presence from="xijinping@anywhere" to="aobama@anywhere" type="subscribed"/> <!-- 允许订阅,相当于QQ里的接受好友添加,既然奥巴马添加习大大为好友,那习大大不能无视吧 所以他就通过将type属性的值设置为subscribed 来接受奥巴马的好友添加请求 --> <presence from="xijinping@anywhere" to="aobama@anywhere" type="subscribe"/> <!-- 习大大心里一想 你奥巴马添加我为好友 也不能跟我聊天啊 因为xmpp协议只允许在双向订阅的情况下才能聊天 所以习大大也向奥巴马发送了添加好友请求 --> <presence from="aobama@anywhere" to="xijinping@anywhere" type="subscribed"/> <!-- 奥巴马一看习大大也请求添加奥巴马为好友 礼尚往来嘛 所以也通过发送type为subscribed的出席节 接受习大大的好友添加请求,现在此时两个人可以聊天 并且对方都在自己的花名册里(好友列表) --> <message from="xijinping@anywhere" to="aobama@anywhere" type="chat"> <body>hello 2B</body> </message> <!-- 习大大发送信息给奥巴马 说:hello 2B --> <message from="aobama@anywhere" to="xijinping@anywhere" type="chat"> <body>SB,你们国家的人权问题啥时候能解决啊?</body> </message> <!-- 奥巴马一看习大大骂他2B 怒了 就回复:SB,你们国家的人权问题啥时候能解决啊? --> <presence type="unavailable"/> <!-- 习大大一看奥巴马正好问中GCD的邪恶了 就赶紧离线 --> <presence from="xijinping@anywhere" to="aobama@anywhere" type="unsubscribe"/> <!-- 然后删除奥巴马 -->