博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
XMPP的一些工作
阅读量:6909 次
发布时间:2019-06-27

本文共 20619 字,大约阅读时间需要 68 分钟。

hot3.png

    最近做了一些xmpp方面的东西,把它写下来。

    最近选用了openfire做xmpp server。所以下面的内容都是基于openfire来做的。

    现在openfire最新的版本是3.7.1,下载下来,用eclipse来编译运行。或者下载安装包,可以安装在windows,Solaris上。

    这两种方式我都用了一下。

    关于在eclipse怎么编译运行openfire,可以参考下面这个链接,写的很全。照着做就可以了。

    

    我的计划是搭建一个HA的openfire系统。具体的讲就是部署两个openfire server,这两个server的domain都配置成一个(这里我用的是xmppservice)。然后在部署一个F5来做负载均衡和failover。这里我没有选择openfire的cluster plugin。因为我们是商业用途,cluster plugin需要买oracle coherence license。

    我的逻辑业务用external component的方式来实现,并连接到openfire server上。 

    在写一个客户端来测试整个系统。

    下面主要把external component的实现和客户端的实现记录下来。

    客户端的实现很简单,主要用到的包是smack。

import org.jivesoftware.smack.Chat;import org.jivesoftware.smack.ConnectionConfiguration;import org.jivesoftware.smack.MessageListener;import org.jivesoftware.smack.PacketListener;import org.jivesoftware.smack.XMPPConnection;import org.jivesoftware.smack.XMPPException;import org.jivesoftware.smack.filter.PacketFilter;import org.jivesoftware.smack.packet.Message;public class XmppClient {		public static void main(String args[]) throws XMPPException{		ConnectionConfiguration config = new ConnectionConfiguration(F5_ip_address,F5_port);		XMPPConnection.DEBUG_ENABLED = true;		XMPPConnection conn2 = new XMPPConnection(config);		boolean auth = conn2.getSASLAuthentication().isAuthenticated();				try {			conn2.connect();		} catch (XMPPException e) {			// TODO Auto-generated catch block			e.printStackTrace();		}		System.out.println(auth);				try {			conn2.login("client_name", "client_password");		} catch (XMPPException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		}		String service = conn2.getServiceName();		System.out.println(service);		PacketListener listener = new SimplePacketListener();		PacketFilter filter = new SimplePacketFilter();		conn2.addPacketListener(listener, filter);		buildMsg(conn2,i);		System.out.println("finished");	}		static void buildMsg(XMPPConnection conn2){		Message req = new Message();		req.setFrom("ilxlf@mymachine_name");		req.setTo("service1@service1.xmppservice");		req.setBody("This is client message");		System.out.println("message sent: "+req.toXML());		conn2.sendPacket(req);		System.out.println("finished");	}}

    这里用到了两个listener,现在没有什么太大的用途,主要用来显示server的response。

import org.jivesoftware.smack.filter.PacketFilter;import org.jivesoftware.smack.packet.Packet;public class SimplePacketFilter implements PacketFilter {	@Override	public boolean accept(Packet arg0) {		// TODO Auto-generated method stub		return true;	}}

import org.jivesoftware.smack.PacketListener;import org.jivesoftware.smack.packet.Packet;public class SimplePacketListener implements PacketListener {	@Override	public void processPacket(Packet arg0) {		// TODO Auto-generated method stub		System.out.println("received: "+arg0.toXML());	}}

下面来说说external component的实现。

先说说配置部署。当我们写了一个external component,我们就需要把他连接到openfire server上。打开openfire的管理页面,默认是在9090端口上。进入之后在server-->server setting -->external components里面配置,默认连接到openfire的5275端口。然后我们需要配置sub-domain和一些访问控制策略。简单点,把sub-domain配好就可以用了(这里我用service1表示sub-domain)。

为了让我们的测试客户端能连接上了,我们在openfire上创建一个测试用户。在Users/Groups-->create new user里面。主要是用户名和密码。对应到上面的代码就是"client_name","client_password"里面的值。

下面就是具体的实现代码。本质上external component可以做成一个war应用,我这里为了方案的验证就做一个普通的java应用。

这里用到的包主要是tinder和whack。 一共三个包。

com.ilxlf.component

org.dom4j.io

org.xmpp.component

后两个包看上去很奇怪,本来是不应该有的。但是在写代码的过程中发现一些问题只能先这么解决一下。

package com.ilxlf.component;import org.jivesoftware.whack.ExternalComponentManager;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.xmpp.component.AbstractComponent;import org.xmpp.component.ComponentException;import org.xmpp.packet.JID;import org.xmpp.packet.Message;public class ExampleComponent extends AbstractComponent {		private static final JID serviceAddress = new JID("service1@service1.xmppservice");	Logger log = LoggerFactory.getLogger(getClass());	public ExampleComponent(){		super(2,1000,true);					}		@Override	public String getDomain() {		// TODO Auto-generated method stub		return "service1";	}	@Override	protected void handleMessage(Message message) {		// TODO Auto-generated method stub		//super.handleMessage(message);		System.out.println(message.toString());		Message response = new Message();		response.setFrom(serviceAddress);		response.setTo(message.getFrom());		response.setBody("give client a response.....");		send(response);	}	@Override	public String getDescription() {		// TODO Auto-generated method stub		return "This is pengfu first xmpp component.";	}	@Override	public String getName() {		// TODO Auto-generated method stub		return "service1.xmppservice";	}			public static void main(String args[]) throws ComponentException{		ExampleComponent comp = new ExampleComponent();		final ExternalComponentManager mgr = new ExternalComponentManager("xmppservice", 5275);		mgr.setSecretKey("service1", "123456");		mgr.addComponent("service1", comp);				while(true){			try {				Thread.sleep(100000);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}		}				}}

package org.dom4j.io;import org.dom4j.*;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import org.xmlpull.v1.XmlPullParserFactory; import java.io.*;import java.net.URL;public class XPPPacketReader {	 	   /**	     * DocumentFactory used to create new document objects	     */	   private DocumentFactory factory;	 	   /**	     * XmlPullParser used to parse XML	     */	   private XmlPullParser xppParser;	 	   /**	     * XmlPullParser used to parse XML	     */	   private XmlPullParserFactory xppFactory;	 	   /**	     * DispatchHandler to call when each Element is encountered	     */	   private DispatchHandler dispatchHandler;	 	 	   public XPPPacketReader() {	   }	 	   public XPPPacketReader(DocumentFactory factory) {	       this.factory = factory;	   }	 	 	   /**	     * 

Reads a Document from the given File

* * @param file is the File to read from. * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. * @throws java.net.MalformedURLException if a URL could not be made for the given File */ public Document read(File file) throws DocumentException, IOException, XmlPullParserException { String systemID = file.getAbsolutePath(); return read(new BufferedReader(new FileReader(file)), systemID); } /** *

Reads a Document from the given URL

* * @param url URL to read from. * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. */ public Document read(URL url) throws DocumentException, IOException, XmlPullParserException { String systemID = url.toExternalForm(); return read(createReader(url.openStream()), systemID); } /** *

Reads a Document from the given URL or filename.

*

*

* If the systemID contains a ':' character then it is * assumed to be a URL otherwise its assumed to be a file name. * If you want finer grained control over this mechansim then please * explicitly pass in either a {@link URL} or a {@link File} instance * instead of a {@link String} to denote the source of the document. *

* * @param systemID is a URL for a document or a file name. * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. * @throws java.net.MalformedURLException if a URL could not be made for the given File */ public Document read(String systemID) throws DocumentException, IOException, XmlPullParserException { if (systemID.indexOf(':') >= 0) { // lets assume its a URL return read(new URL(systemID)); } else { // lets assume that we are given a file name return read(new File(systemID)); } } /** *

Reads a Document from the given stream

* * @param in InputStream to read from. * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. */ public Document read(InputStream in) throws DocumentException, IOException, XmlPullParserException { return read(createReader(in)); } /** *

Reads a Document from the given Reader

* * @param reader is the reader for the input * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. */ public Document read(Reader reader) throws DocumentException, IOException, XmlPullParserException { getXPPParser().setInput(reader); return parseDocument(); } /** *

Reads a Document from the given array of characters

* * @param text is the text to parse * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. */ public Document read(char[] text) throws DocumentException, IOException, XmlPullParserException { getXPPParser().setInput(new CharArrayReader(text)); return parseDocument(); } /** *

Reads a Document from the given stream

* * @param in InputStream to read from. * @param systemID is the URI for the input * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. */ public Document read(InputStream in, String systemID) throws DocumentException, IOException, XmlPullParserException { return read(createReader(in), systemID); } /** *

Reads a Document from the given Reader

* * @param reader is the reader for the input * @param systemID is the URI for the input * @return the newly created Document instance * @throws DocumentException if an error occurs during parsing. */ public Document read(Reader reader, String systemID) throws DocumentException, IOException, XmlPullParserException { Document document = read(reader); document.setName(systemID); return document; } // Properties //------------------------------------------------------------------------- public XmlPullParser getXPPParser() throws XmlPullParserException { if (xppParser == null) { xppParser = getXPPFactory().newPullParser(); } return xppParser; } public XmlPullParserFactory getXPPFactory() throws XmlPullParserException { if (xppFactory == null) { xppFactory = XmlPullParserFactory.newInstance(); } xppFactory.setNamespaceAware(true); return xppFactory; } public void setXPPFactory(XmlPullParserFactory xppFactory) { this.xppFactory = xppFactory; } /** * @return the DocumentFactory used to create document objects */ public DocumentFactory getDocumentFactory() { if (factory == null) { factory = DocumentFactory.getInstance(); } return factory; } /** *

This sets the DocumentFactory used to create new documents. * This method allows the building of custom DOM4J tree objects to be implemented * easily using a custom derivation of {@link DocumentFactory}

* * @param factory DocumentFactory used to create DOM4J objects */ public void setDocumentFactory(DocumentFactory factory) { this.factory = factory; } /** * Adds the ElementHandler to be called when the * specified path is encounted. * * @param path is the path to be handled * @param handler is the ElementHandler to be called * by the event based processor. */ public void addHandler(String path, ElementHandler handler) { getDispatchHandler().addHandler(path, handler); } /** * Removes the ElementHandler from the event based * processor, for the specified path. * * @param path is the path to remove the ElementHandler for. */ public void removeHandler(String path) { getDispatchHandler().removeHandler(path); } /** * When multiple ElementHandler instances have been * registered, this will set a default ElementHandler * to be called for any path which does NOT have a handler * registered. * * @param handler is the ElementHandler to be called * by the event based processor. */ public void setDefaultHandler(ElementHandler handler) { getDispatchHandler().setDefaultHandler(handler); } // Implementation methods //------------------------------------------------------------------------- public Document parseDocument() throws DocumentException, IOException, XmlPullParserException { DocumentFactory df = getDocumentFactory(); Document document = df.createDocument(); Element parent = null; XmlPullParser pp = getXPPParser(); int count = 0; while (true) { int type = -1; type = pp.nextToken(); switch (type) { case XmlPullParser.PROCESSING_INSTRUCTION: { String text = pp.getText(); int loc = text.indexOf(" "); if (loc >= 0) { document.addProcessingInstruction(text.substring(0, loc), text.substring(loc + 1)); } else document.addProcessingInstruction(text, ""); break; } case XmlPullParser.COMMENT: { if (parent != null) parent.addComment(pp.getText()); else document.addComment(pp.getText()); break; } case XmlPullParser.CDSECT: { String text = pp.getText(); if (parent != null) { parent.addCDATA(text); } else { if (text.trim().length() > 0) { throw new DocumentException("Cannot have text content outside of the root document"); } } break; } case XmlPullParser.ENTITY_REF: { String text = pp.getText(); if (parent != null) { parent.addText(text); } else { if (text.trim().length() > 0) { throw new DocumentException("Cannot have an entityref outside of the root document"); } } break; } case XmlPullParser.END_DOCUMENT: { return document; } case XmlPullParser.START_TAG: { QName qname = (pp.getPrefix() == null) ? df.createQName(pp.getName(), pp.getNamespace()) : df.createQName(pp.getName(), pp.getPrefix(), pp.getNamespace()); Element newElement = null; // Do not include the namespace if this is the start tag of a new packet // This avoids including "jabber:client", "jabber:server" or // "jabber:component:accept" if ("jabber:client".equals(qname.getNamespaceURI()) || "jabber:server".equals(qname.getNamespaceURI()) || "jabber:component:accept".equals(qname.getNamespaceURI()) || "http://jabber.org/protocol/httpbind".equals(qname.getNamespaceURI())) { newElement = df.createElement(pp.getName()); } else { newElement = df.createElement(qname); } int nsStart = pp.getNamespaceCount(pp.getDepth() - 1); int nsEnd = pp.getNamespaceCount(pp.getDepth()); for (int i = nsStart; i < nsEnd; i++) if (pp.getNamespacePrefix(i) != null) newElement.addNamespace(pp.getNamespacePrefix(i), pp.getNamespaceUri(i)); for (int i = 0; i < pp.getAttributeCount(); i++) { QName qa = (pp.getAttributePrefix(i) == null) ? df.createQName(pp.getAttributeName(i)) : df.createQName(pp.getAttributeName(i), pp.getAttributePrefix(i), pp.getAttributeNamespace(i)); newElement.addAttribute(qa, pp.getAttributeValue(i)); } if (parent != null) { parent.add(newElement); } else { document.add(newElement); } parent = newElement; count++; break; } case XmlPullParser.END_TAG: { if (parent != null) { parent = parent.getParent(); } count--; if (count < 1) { return document; } break; } case XmlPullParser.TEXT: { String text = pp.getText(); if (parent != null) { parent.addText(text); } else { if (text.trim().length() > 0) { throw new DocumentException("Cannot have text content outside of the root document"); } } break; } default: { ; } } } } protected DispatchHandler getDispatchHandler() { if (dispatchHandler == null) { dispatchHandler = new DispatchHandler(); } return dispatchHandler; } protected void setDispatchHandler(DispatchHandler dispatchHandler) { this.dispatchHandler = dispatchHandler; } /** * Factory method to create a Reader from the given InputStream. */ protected Reader createReader(InputStream in) throws IOException { return new BufferedReader(new InputStreamReader(in)); } } /* * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided * that the following conditions are met: * * 1. Redistributions of source code must retain copyright * statements and notices. Redistributions must also contain a * copy of this document. * * 2. Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. The name "DOM4J" must not be used to endorse or promote * products derived from this Software without prior written * permission of MetaStuff, Ltd. For written permission, * please contact dom4j-info@metastuff.com. * * 4. Products derived from this Software may not be called "DOM4J" * nor may "DOM4J" appear in their names without prior written * permission of MetaStuff, Ltd. DOM4J is a registered * trademark of MetaStuff, Ltd. * * 5. Due credit should be given to the DOM4J Project - * http://www.dom4j.org * * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved. * * $Id: XPPPacketReader.java 6408 2006-12-15 23:35:30Z gato $ */

package org.xmpp.component;public interface Log {}

用到的jar包是:

下一步的工作:

如果一个server连接多个相同业务的external component,是否可以在这些component之间做负载均衡和failover。

openfire的pub-sub的使用。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

dd

转载于:https://my.oschina.net/u/145002/blog/33216

你可能感兴趣的文章
svn服务器搭建
查看>>
[官方翻译]RabbitMQ生产上线前准备
查看>>
Haskell开发以太坊智能合约
查看>>
C++除零异常
查看>>
css的兼容问题汇总
查看>>
android apk 防止反编译技术第五篇-完整性校验(转)
查看>>
ios优秀开发者笔记汇总
查看>>
CSS 异步加载技术 不影响页面渲染
查看>>
我的友情链接
查看>>
angular学习资源
查看>>
我的友情链接
查看>>
Python [3] optparse、sys、hashlib模块
查看>>
等待事件之Log File Sync
查看>>
DML并行度限制
查看>>
python mix-in
查看>>
oracle的启动和关闭
查看>>
Docker 基础技术:Linux Namespace(下)
查看>>
VMwareWorkstation 15 木有響應 我勒個去……硬盤智障?
查看>>
如何用好 Google 等搜索引擎
查看>>
【QQ和新浪微博登陆第三方的简单实现】
查看>>