博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
openfire连接登陆优化方案
阅读量:4953 次
发布时间:2019-06-12

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

client登陆openfire,大概总共须要9个来回才完毕登录。

在2G情况下。就表现为client登录特别慢,所以,为解决问题,对openfire进行了例如以下优化

openfire的连接、登陆过程分为几个步骤,完整报文例如以下。总共分为9个round trip:

===================================================================================================================

1  STREAM

RECV:<stream:stream to="jacklin-pc" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">

SENT:<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="jacklin-pc" id="96508a6d" xml:lang="en" version="1.0">
SENT:<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls><mechanisms xmlns="urn:ietf:p 
arams:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>JIVE-SHAREDSECRET</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/><register xmlns="http://jabber.org/features/iq-register"/></stream:features>

2  TLS

RECV:<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

SENT:<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

3  STREAM

RECV:<stream:stream to="jacklin-pc" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">

SENT:<?

xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="jacklin-pc" id="96508a6d" xml:lang="en" version="1.0"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>JIVE-SHAREDSECRET</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/><register xmlns="http://jabber.org/features/iq-register"/></stream:features>

4  SASL

RECV:<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cmVhbG09ImphY2tsaW4tcGMiLG5vbmNlPSJMamw2RGt4Y3hGSDZxb2dTRE55Nmw2VkYreVQ2YjROMFlTa1BBSlZqIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz</auth>

SENT:<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></success>

5  STREAM

RECV:<stream:stream to="jacklin-pc" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">

SENT:<?

xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="jacklin-pc" id="96508a6d" xml:lang="en" version="1.0"><stream:features><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>

6  BIND

RECV:<iq id="SfW08-0" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>Spark 2.6.3</resource></bind></iq>

SENT:<iq type="result" id="SfW08-0" to="jacklin-pc/96508a6d"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>test001@jacklin-pc/Spark 2.6.3</jid></bind></iq>

7  SESSION

RECV:<iq id="SfW08-1" type="set"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>

SENT:<iq type="result" id="SfW08-1" to="test001@jacklin-pc/Spark 2.6.3"/>
8  PRESENCE

RECV:<presence id="SfW08-6"><status>在线</status><priority>1</priority></presence>

9  ZLIB

RECV:<compress xmlns='http://jabber.org/protocol/compress'><method>zlib</method></compress>

SENT:<compressed xmlns='http://jabber.org/protocol/compress'/>

===================================================================================================================

1  STREAM优化

当中STREAM类似查询server功能,server会把server的特性返回给client,比如SASL策略,iq-auth,zlib压缩,xmpp-bind等等。事实上,假设是内部定制的系统,这些特性server与client都是共知的,所以不须要查询,全然能够省略这些步骤。

可是,我发现,在client第一次发送stream时,是须要初始化一些内容的。所以,须要再例如以下地方。增加例如以下代码:

org.jivesoftware.openfire.nio.ConnectionHandler

@Override	public void sessionOpened(IoSession session) throws Exception {		// Create a new XML parser for the new connection. The parser will be		// used by the XMPPDecoder filter.		final XMLLightweightParser parser = new XMLLightweightParser(CHARSET);		session.setAttribute(XML_PARSER, parser);		// Create a new NIOConnection for the new session		final NIOConnection connection = createNIOConnection(session);		session.setAttribute(CONNECTION, connection);		session.setAttribute(HANDLER, createStanzaHandler(connection));		// Set the max time a connection can be idle before closing it. This		// amount of seconds		// is divided in two, as Openfire will ping idle clients first (at 50%		// of the max idle time)		// before disconnecting them (at 100% of the max idle time). This		// prevents Openfire from		// removing connections without warning.		final int idleTime = getMaxIdleTime() / 2;		if (idleTime > 0) {			session.setIdleTime(IdleStatus.READER_IDLE, idleTime);		}		// ADD LOCALSESSION START===========================================================		Log.info("[DO LOCALSESSION]");		int hashCode = Thread.currentThread().hashCode();		XMPPPacketReader parser1 = parsers.get(hashCode);		if (parser1 == null) {			parser1 = new XMPPPacketReader();			parser1.setXPPFactory(factory);			parsers.put(hashCode, parser1);		}		String msg = "
"; StanzaHandler handler = (StanzaHandler) session.getAttribute(HANDLER); try { handler.process(msg, parser1); } catch (Exception e) { Log.error( "Closing connection due to error while processing message: " + msg, e); connection.close(); } // ADD LOCALSESSION END============================================================== }
此目的是让server在client建立连接阶段就初始化client的资源。

2  SESSION

session事实上从server端看,仅仅是回复了一下client,并没有起什么作用,所以client能够不发这段报文,server端不须要修改。server端处理步骤例如以下。

org.jivesoftware.openfire.handler.IQSessionEstablishmentHandler

public class IQSessionEstablishmentHandler extends IQHandler {    private IQHandlerInfo info;    public IQSessionEstablishmentHandler() {        super("Session Establishment handler");        info = new IQHandlerInfo("session", "urn:ietf:params:xml:ns:xmpp-session");    }    @Override	public IQ handleIQ(IQ packet) throws UnauthorizedException {        // Just answer that the session has been activated        IQ reply = IQ.createResultIQ(packet);        return reply;    }    @Override	public IQHandlerInfo getInfo() {        return info;    }}
3  BIND,PRESENCE,ZLIB

事实上PRESENCE和ZLIB能够在clientBIND操作之后。server端直接进行,不须要client再次协商。所以。我在下面代码。进行了下面修改:

org.jivesoftware.openfire.handler.IQBindHandler

@Override	public IQ handleIQ(IQ packet) throws UnauthorizedException {		LocalClientSession session = (LocalClientSession) sessionManager				.getSession(packet.getFrom());		// If no session was found then answer an error (if possible)		if (session == null) {			Log.error("Error during resource binding. Session not found in "					+ sessionManager.getPreAuthenticatedKeys() + " for key "					+ packet.getFrom());			// This error packet will probably won't make it through			IQ reply = IQ.createResultIQ(packet);			reply.setChildElement(packet.getChildElement().createCopy());			reply.setError(PacketError.Condition.internal_server_error);			return reply;		}		IQ reply = IQ.createResultIQ(packet);		Element child = reply.setChildElement("bind",				"urn:ietf:params:xml:ns:xmpp-bind");		// Check if the client specified a desired resource		String resource = packet.getChildElement().elementTextTrim("resource");		if (resource == null || resource.length() == 0) {			// None was defined so use the random generated resource			resource = session.getAddress().getResource();		} else {			// Check that the desired resource is valid			try {				resource = JID.resourceprep(resource);			} catch (StringprepException e) {				reply.setChildElement(packet.getChildElement().createCopy());				reply.setError(PacketError.Condition.jid_malformed);				// Send the error directly since a route does not exist at this				// point.				session.process(reply);				return null;			}		}		// Get the token that was generated during the SASL authentication		AuthToken authToken = session.getAuthToken();		if (authToken == null) {			// User must be authenticated before binding a resource			reply.setChildElement(packet.getChildElement().createCopy());			reply.setError(PacketError.Condition.not_authorized);			// Send the error directly since a route does not exist at this			// point.			session.process(reply);			return reply;		}		if (authToken.isAnonymous()) {			// User used ANONYMOUS SASL so initialize the session as an			// anonymous login			session.setAnonymousAuth();		} else {			String username = authToken.getUsername().toLowerCase();			// If a session already exists with the requested JID, then check to			// see			// if we should kick it off or refuse the new connection			ClientSession oldSession = routingTable.getClientRoute(new JID(					username, serverName, resource, true));			if (oldSession != null) {				try {					int conflictLimit = sessionManager.getConflictKickLimit();					if (conflictLimit == SessionManager.NEVER_KICK) {						reply.setChildElement(packet.getChildElement()								.createCopy());						reply.setError(PacketError.Condition.conflict);						// Send the error directly since a route does not exist						// at this point.						session.process(reply);						return null;					}					int conflictCount = oldSession.incrementConflictCount();					if (conflictCount > conflictLimit) {						// Kick out the old connection that is conflicting with						// the new one						StreamError error = new StreamError(								StreamError.Condition.conflict);						oldSession.deliverRawText(error.toXML());						oldSession.close();					} else {						reply.setChildElement(packet.getChildElement()								.createCopy());						reply.setError(PacketError.Condition.conflict);						// Send the error directly since a route does not exist						// at this point.						session.process(reply);						return null;					}				} catch (Exception e) {					Log.error("Error during login", e);				}			}			// If the connection was not refused due to conflict, log the user			// in			session.setAuthToken(authToken, resource);		}		child.addElement("jid").setText(session.getAddress().toString());		// Send the response directly since a route does not exist at this		// point.		session.process(reply);		// After the client has been informed, inform all listeners as well.		SessionEventDispatcher.dispatchEvent(session,				SessionEventDispatcher.EventType.resource_bound);		// ADD COMPRESSION START==================================================		 session.getConnection().addCompression();		 session.getConnection().startCompression();		 Log.info("[DO COMPRESSION]");		// ADD COMPRESSION END====================================================		 		 		// ADD PRESENCE START====================================================		String domain = XMPPServer.getInstance().getServerInfo()				.getXMPPDomain();		Presence pp = new Presence();		pp.setFrom(session.getAddress().toString());		// pp.setTo(domain);		XMPPServer.getInstance().getPacketRouter().route(pp);		Log.info("[DO PRESENCE]:"+ pp.toXML());		// ADD PRESENCE END====================================================		return null;	}

经过以上优化之后,server与client的协商仅仅剩下3个round trip。步骤例如以下:

2  TLS

RECV:<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

SENT:<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

4  SASL

RECV:<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cmVhbG09ImphY2tsaW4tcGMiLG5vbmNlPSJMamw2RGt4Y3hGSDZxb2dTRE55Nmw2VkYreVQ2YjROMFlTa1BBSlZqIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz</auth>

SENT:<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></success>

6  BIND

RECV:<iq id="SfW08-0" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>Spark 2.6.3</resource></bind></iq>

SENT:<iq type="result" id="SfW08-0" to="jacklin-pc/96508a6d"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>test001@jacklin-pc/Spark 2.6.3</jid></bind></iq>

client依照例如以下节奏发送报文。并进行操作就能够了。client改动代码。在这里不做描写叙述,请改动者自行尝试

转载于:https://www.cnblogs.com/mengfanrong/p/5240074.html

你可能感兴趣的文章
[luogu4201][bzoj1063]设计路线【树形DP】
查看>>
手机抓包-手机劫持域名到指定服务器
查看>>
被放逐的皇后 金建云
查看>>
Javascript 有用参考函数
查看>>
点群的判别(三)
查看>>
GNSS 使用DFT算法 能量损耗仿真
查看>>
网页抓取 总结
查看>>
【转】Simulink模型架构指导
查看>>
MYSQL数据库的导出的几种方法
查看>>
SQL Server-5种常见的约束
查看>>
硬件之美
查看>>
[转载]java开发中的23种设计模式
查看>>
表格的拖拽功能
查看>>
函数的形参和实参
查看>>
文字过长 用 ... 表示 CSS实现单行、多行文本溢出显示省略号
查看>>
1Caesar加密
查看>>
【TP SRM 703 div2 500】 GCDGraph
查看>>
MapReduce 重要组件——Recordreader组件 [转]
查看>>
webdriver api
查看>>
转载-FileZilla Server源码分析(1)
查看>>