设为首页收藏本站

Scripts 学盟

 找回密码
 加入学盟

QQ登录

只需一步,快速开始

查看: 4776|回复: 7
打印 上一主题 下一主题

求openfire源码解读 [复制链接]

Rank: 8Rank: 8

跳转到指定楼层
1#
那个谁 发表于 2011-7-6 16:32:03 |只看该作者 |倒序浏览
20金钱
   如题、欢迎各种党。满意后结贴。

最佳答案

momo 查看完整内容

据说这二十分不给漠漠的话,lz会倒霉
分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
分享分享0 收藏收藏0

Rank: 8Rank: 8

2#
momo 发表于 2011-7-6 16:32:04 |只看该作者
据说这二十分不给漠漠的话,lz会倒霉
过了爱做梦的年纪
轰轰烈烈不如平静

使用道具 举报

Rank: 8Rank: 8

3#
那个谁 发表于 2011-7-6 16:40:20 |只看该作者
  1. Openfire和MINA
  2. 看了几天的openfire,网上的资料太少了,只有一个国外的网站不错,http://www.igniterealtime.org/ ,其他的只能自己摸索了。
  3. openfire启动:
  4. ServerStarter
  5. 会加载 org.jivesoftware.openfire.XMPPServer
  6. 在XMPPServer会加载一系列模块
  7. 其中的ConnectionManagerImpl 是连接模块
  8. // Load this module always last since we don't want to start listening for clients  
  9.       // before the rest of the modules have been started        loadModule(ConnectionManagerImpl.class.getName());
  10. ConnectionManagerImpl 会启动一系列的监听。
  11. 其中的createClientListeners和startClientListeners是我比较关心的,先看看在这里面openfire都做了什么!
  12. private void createClientListeners() {      
  13.   // Start clients plain socket unless it's been disabled.     
  14.     if (isClientListenerEnabled()) {           
  15. // Create SocketAcceptor with correct number of processors         
  16.    socketAcceptor = buildSocketAcceptor();      
  17.       // Customize Executor that will be used by processors to process incoming stanzas        
  18.      ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance("client" );        
  19.     int eventThreads = JiveGlobals.getIntProperty("xmpp.client.processing.threads" , 16);      
  20.       ThreadPoolExecutor eventExecutor = (ThreadPoolExecutor)threadModel.getExecutor();            eventExecutor.setCorePoolSize(eventThreads + 1);         
  21.    eventExecutor.setMaximumPoolSize(eventThreads + 1);         
  22.   eventExecutor.setKeepAliveTime(60, TimeUnit.SECONDS );           
  23. socketAcceptor .getDefaultConfig().setThreadModel(threadModel);            // Add the XMPP codec filter             socketAcceptor .getFilterChain().addFirst("xmpp" , new ProtocolCodecFilter(new XMPPCodecFactory()));      
  24.      // Kill sessions whose outgoing queues keep growing and fail to send traffic            
  25. socketAcceptor .getFilterChain().addAfter("xmpp" , "outCap ", new StalledSessionsFilter());        }    }
  26. 对了这里就是和用的mina框架去做联网处理,首先设置mina框架的线程池,然后把由XMPPCodecFactory做为 ProtocolCodecFilter的chain添加到FilterChain中!
  27. 然后
  28. private void startClientListeners(String localIPAddress) {   
  29.     // Start clients plain socket unless it's been disabled.      
  30.   if (isClientListenerEnabled()) {         
  31.    int port = getClientListenerPort();        
  32.     try {                // Listen on a specific network interface if it has been set.         
  33.       String interfaceName = JiveGlobals.getXMLProperty("network.interface");           
  34.      InetAddress bindInterface = nu``ll;              
  35.   if (interfaceName != null) {                  
  36. if (interfaceName.trim().length() > 0) {                  
  37.       bindInterface = InetAddress.getByName(interfaceName);              
  38.       }                }               
  39. // Start accepting connections            
  40.     socketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler(serverName));                ports.add(new ServerPort(port, serverName, localIPAddress, false, null, ServerPort.Type.client));      
  41.          List<String> params = new ArrayList<String>();            
  42.     params.add(Integer.toString(port));           
  43.      Log.info(LocaleUtils.getLocalizedString("startup.plain", params));         
  44.    } catch (Exception e) {            
  45.     System.err.println("Error starting XMPP listener on port " + port + ": " +  e.getMessage());  
  46. Log.error(LocaleUtils.getLocalizedString("admin.error.socket-setup"), e);   
  47.        }        }    }
  48.   socketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler(serverName));
  49. 将ClientConnectionHandler作为数据处理
  50. 服务器去监听5222端口去了,mina真方便!
  51. 关于MINA框架可以去网上找找资料,这里就不说了。
  52.   这里要说下MINA中的IoHandler这个接口,IoHandler是最终面对用户的接口,看下这个接口中的方法:

  53. public interface IoHandler {   
  54. /**     * Invoked from an I/O processor thread when a new connection has been created.   
  55. * Because this method is supposed to be called from the same thread that   
  56. * handles I/O of multiple sessions, please implement this method to perform   
  57. * tasks that consumes minimal amount of time such as socket parameter   
  58. * and user-defined session attribute initialization.   
  59. */   
  60. void sessionCreated(IoSession session) throws Exception;   
  61. /**
  62. * Invoked when a connection has been opened.  This method is invoked after     
  63. * {@link #sessionCreated(IoSession)}.  The biggest difference from     
  64. * {@link #sessionCreated(IoSession)} is that it's invoked from other thread     
  65. * than an I/O processor thread once thread model is configured properly.     
  66. */     
  67. void sessionOpened(IoSession session) throws Exception;   
  68. /**
  69. * Invoked when a connection is closed.     
  70. */     void sessionClosed(IoSession session) throws Exception;   
  71. /**
  72. * Invoked with the related {@link IdleStatus} when a connection becomes idle.     
  73. * This method is not invoked if the transport type is UDP; it's a known bug,     
  74. * and will be fixed in 2.0.     
  75. */
  76. void sessionIdle(IoSession session, IdleStatus status) throws Exception;   
  77. /**
  78. * Invoked when any exception is thrown by user {@link IoHandler}     
  79. * implementation or by MINA.  If <code>cause</code> is an instance of     
  80. * {@link IOException}, MINA will close the connection automatically.     
  81. */   
  82. void exceptionCaught(IoSession session, Throwable cause) throws Exception;   
  83. /**
  84. * Invoked when a message is received.     
  85. */     
  86. void messageReceived(IoSession session, Object message) throws Exception;   
  87. /**
  88. * Invoked when a message written by {@link IoSession#write(Object)} is     
  89. * sent out.     
  90. */     
  91. void messageSent(IoSession session, Object message) throws Exception;}

  92. 在mina中实现这个接口的类是IoHandlerAdapter 这个类
  93. /**
  94. * An abstract adapter class for {@link IoHandler}.  You can extend this
  95. * class and selectively override required event handler methods only.  All
  96. * methods do nothing by default.
  97. *
  98. * @author The Apache MINA Project (dev@mina.apache.org)
  99. * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (jeu, 26 jun 2008) $
  100. */
  101. public class IoHandlerAdapter implements IoHandler {   
  102. private final Logger logger = LoggerFactory.getLogger(getClass());
  103.     public void sessionCreated(IoSession session) throws Exception {
  104.         }   
  105.         public void sessionOpened(IoSession session) throws Exception {
  106.         }   
  107.         public void sessionClosed(IoSession session) throws Exception {
  108.     }   
  109.         public void sessionIdle(IoSession session, IdleStatus status)throws Exception {
  110.         }   
  111.         public void exceptionCaught(IoSession session, Throwable cause)throws Exception {
  112.         if (logger.isWarnEnabled()) {   
  113.         logger.warn("EXCEPTION, please implement "+ getClass().getName()+ ".exceptionCaught() for proper handling:", cause);        
  114.         }   
  115.         }   
  116.         public void messageReceived(IoSession session, Object message)throws Exception {  
  117.         }   
  118.         public void messageSent(IoSession session, Object message) throws Exception {   
  119.         }
  120. }

  121. 接下来转到openfire,在openfire中ConnectionHandler类继承自IoHandlerAdapter,也就充当着最后要面对用户的角色。
  122. public abstract class ConnectionHandler extends IoHandlerAdapter
复制代码

使用道具 举报

Rank: 8Rank: 8

4#
那个谁 发表于 2011-7-7 09:43:55 |只看该作者
Openfire的socket网络连接包括:

<!--[if !supportLists]-->1.       <!--[endif]-->服务器和服务器之间的连接(监听在端口5269)

<!--[if !supportLists]-->2.       <!--[endif]-->外部组件和服务器之间的连接(监听在端口5275)

<!--[if !supportLists]-->3.       <!--[endif]-->多元(complex)连接(监听在端口5269)

<!--[if !supportLists]-->4.       <!--[endif]-->客户端和服务器的连接(监听在端口5222)

<!--[if !supportLists]-->5.       <!--[endif]-->和客户端通过TLS/SSL3.0和服务器的连接。(监听在端口5223)

这些连接都是通过ConnectionManager接口实现管理的,程序中对ConnectionManager接口的实现类是ConnectionManagerImpl,它是作为一个模块(Module)类加载到服务器中的。

使用道具 举报

Rank: 8Rank: 8

5#
那个谁 发表于 2011-7-7 10:11:14 |只看该作者
下面分析的是客户端和服务器的连接。



在ConnectionManagerImpl中是通过调用startClientListeners方法来初始化和开始端口监听的。

<!--[endif]-->在startClientListeners方法使用的是Apache的Mina框架来实现网络连接的,Mina框架的模式如下:

IoFilter:

       IoFilter为MINA的功能扩展提供了接口。它拦截所有的IO事件进行事件的预处理和后处理。它与Servlet中的filter机制十分相似。多个IoFilter存放在IoFilterChain中

       IoFilter能够实现以下功能:

              数据转换

              事件日志

              性能检测

       在Openfire中主要用filter这种机制来进行数据转换。

Protocol Codec Factory:

       Protocol Codec Factory提供了方便的Protocol支持,通过它的Encoder和Decoder,可以方便的扩展并支持各种基于Socket的网络协议,比如HTTP服务器、FTP服务器、Telnet服务器等等。

       要实现自己的编码/解码器(codec)只需要实现interface: ProtocolCodecFactory即可,在Openfire中实现ProtocolCodecFactory的类为XMPPCodecFactory。

IoHandler:

    MINA中,所有的业务逻辑都有实现了IoHandler的class完成    ,当事件发生时,将触发IoHandler中的方法:

           sessionCreated

sessionOpened

sessionClosed

sessionIdle

exceptionCaught

messageReceived

messageSent

       在Openfire中客户端和服务器连接的IoHandler实现类是ClientConnectionHandler,它是从ConnectionHandler中继承来的。

startClientListeners方法首先为Mian框架设置线程池,再将一个由XMPPCodecFactory作为Protocol Codec Factory的Filter放入到FilterChain中,然后绑定到端口5222,并将ClientConnectionHandler作为IoHandler对数据进行处理。完成这些步骤后Openfire就在5222等待客户端的连接。

使用道具 举报

Rank: 8Rank: 8

6#
那个谁 发表于 2011-7-7 10:16:45 |只看该作者
客户端连接的处理过程:



当有客户端进行连接时根据Mina框架的模式首先调用的是sessionOpened方法。

       sessionOpened首先为此新连接构造了一个parser(XMLLightWeightParser),这个parser是专门给XMPPDecoder(是XMPPCodecFactory的解码器类)使用的,再创建一个Openfire的Connection类实例connection和一个StanzaHandler的实例。最后将以上的parser, connection和StanzaHandler的实例存放在Mina的session中,以便以后使用。

       当有数据发送过来时,Mina框架会调用messageReceived方法

       messageReceived首先从Mina的session中得到在sessionOpened方法中创建的StanzaHandler实例handler,然后从parsers中得到一个parser(如果parsers中没有可以创建一个新的实例)(注意这个parser和在sessionOpened方法中创建的parser不同,这个parser是用来处理Stanza的,而在sessionOpened方法中创建的parser是在filter中用来解码的,一句话说就是在sessionOpened方法中创建的parser是更低一层的parser)。最后将xml数据包交给StanzaHander的实例hander进行处理。

       StanzaHander的实例hander处理xml数据包的过程

       StanzaHander首先判断xml数据包的类型,.如果数据包以“<stream:stream”打头那么说明客户端刚刚连接,需要初始化通信(符合XMPP协议)Openfire首先为此客户端建立一个与客户端JID相关的ClientSession,而后与客户端交互协商例如是否使用SSL,是否使用压缩等问题。当协商完成之后进入正常通信阶段,则可以将xml数据包交给这个用户的ClientSession进行派送(deliever),经过派送数据包可以发送给PacketRouteImpl模块进行处理。



使用道具 举报

Rank: 6Rank: 6

7#
Yisin 发表于 2011-7-10 12:36:55 来自手机 |只看该作者
把分给我好了
路不好走,你却依旧满眼的爱,找不到理由...

使用道具 举报

管理员

超级大菜鸟

Rank: 9Rank: 9Rank: 9

8#
混混@普宁.中国 实名认证  发表于 2011-7-16 01:23:13 |只看该作者
给我更好

使用道具 举报

您需要登录后才可以回帖 登录 | 加入学盟

手机版|Scripts 学盟   |

GMT+8, 2024-5-6 08:39 , Processed in 1.069107 second(s), 13 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部