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 = "<stream:stream to='jacklin-pc' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"; 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改动代码。在这里不做描写叙述,请改动者自行尝试

openfire连接登陆优化方案的更多相关文章

  1. Tomcat 配置详解/优化方案

     转自:http://blog.csdn.net/cicada688/article/details/14451541 Service.xml Server.xml配置文件用于对整个容器进行相关的配置 ...

  2. tomcat配置详解/优化方案

    Service.xml Server.xml配置文件用于对整个容器进行相关的配置. <Server>元素:是整个配置文件的根元素.表示整个Catalina容器. 属性:className: ...

  3. (转)Web性能优化方案

    第一章 打开网站慢现状分析 在公司访问部署在IDC机房的VIP网站时会感觉很慢.是什么原因造成的?为了缩短页面的响应时间,改进我们的用户体验,我们需要知道用户的时间花在等待什么东西上. 可以跟踪一下我 ...

  4. Redmine性能优化方案

    近来公司redmine服务器表现很糟糕,在16核,64GRAM的机器上,压测结果竟然只有每秒5~7个请求,部分页面一个都出不来. 以下是我对Redmine性能优化方案: redmine服务器性能问题排 ...

  5. Android App罕见错误和优化方案

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 1.App如果被定义一个有参数构造函数,那么需要再定义一个无参数的,如果不则会在某些情况下初始化失败 ...

  6. mysql大内存高性能优化方案

    mysql优化是一个相对来说比较重要的事情了,特别像对mysql读写比较多的网站就显得非常重要了,下面我们来介绍mysql大内存高性能优化方案 8G内存下MySQL的优化 按照下面的设置试试看:key ...

  7. Openfire服务器MySQL优化

    Openfire服务器MySQL优化: [root@iZ28g4ctd7tZ ~]# mysql -u root -p XXXXX mysql> show processlist; +----- ...

  8. Adapter优化方案的探索

    概要:使用Adapter的注意事项与优化方案本文的例子都可以在结尾处的示例代码连接中看到并下载,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request. ...

  9. Web性能优化方案

    第一章 打开网站慢现状分析 在公司访问部署在IDC机房的VIP网站时会感觉很慢.是什么原因造成的?为了缩短页面的响应时间,改进我们的用户体验,我们需要知道用户的时间花在等待什么东西上. 可以跟踪一下我 ...

随机推荐

  1. 1201.1——Vim编辑器的相关操作

    一 vi的操作模式 vi提供两种操作模式:输入模式(insert mode)和指令模式(command mode).在输入模式下,用户可输入文本资料.在指令模式下,可进行删除.修改等各种编辑动作. 在 ...

  2. angularjs不同页面间controller传参方式,使用service封装sessionStorage

    这里分享一个我在实际项目中,使用service封装的一个依赖sessionStorage的传参服务. 这里先说下大背景,在我们的实际开发中,登陆之后一般会存在一个token,这个token将会贯穿全场 ...

  3. PLSQL developer连接不上64位Oracle的解决方法

    PLSQL developer连接不上64位Oracle的解决方法 64位下装Oracle 11g 64位,PLSQL Developer使用出现问题. 问题描述: 登录对话框中,数据库下拉框为空: ...

  4. angular启动过程分析

    启动过程 步骤一 用自执行函数在代码完成加载后立即执行 function(window, document, undefined) 在window上暴露一个唯一的全局对象angular,Line250 ...

  5. 兄弟连面试宝典php

    学历这个事情是企业招聘经常设置的一道门槛,我们不能说学历高就能力高,也不能说学历低能力就差,那如何辩证回答这个问题呢?回答提示:学历不一定完全代表能力,虽然我的学历不够硬但是我会在技术上更努力更认真, ...

  6. js识别终端类型

    <script type="text/javascript"> function browserRedirect() { var sUserAgent= navigat ...

  7. adb :unknown host service

    adb 没法重启   现象:C:\Users\John>adb shell             adb server is out of date.  killing...          ...

  8. ImageView加ImageSwitch制作图片浏览器

    Main /** 图片浏览器*/public class MainActivity extends Activity implements ViewFactory{private Gallery ga ...

  9. Dedecms v5.7包含上传漏洞利用

    Title:Dedecms v5.7包含上传漏洞利用 --2012-09-21 10:16 注册,登录,免邮箱验证. up.htm ---------------------------------- ...

  10. 转 Jona Dany 一个20年架构师程序员的经验总结

    1.估算问题解决所需要的时间,为自己定一个时间限制,1小时,30分钟,15分钟.如果这期间不能解决问题,那就去寻求帮助.不要做超级堆码员. 2.编程语言是一种语言,只是一种语言.只要理解一种语言的原理 ...