ConnectionManagerImpl 模块学习

本文深入探讨了ConnectionManagerImpl模块在服务器连接管理中的作用,包括其实现的接口、初始化过程、创建监听器及启动流程,以及如何处理证书事件。详细解释了CertificateEventListener接口的实现和ConnectionManager接口的特性,展示了模块如何通过创建和启动不同类型的监听器来管理服务器与客户端之间的连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ConnectionManagerImpl 实现了两个接口ConnectionManager和CertificateEventListener,并继承自BasicModule。


CertificateEventListener顾名思义,即为证书事件监听器,所有需要对证书变动进行相应行为的类或模块均要实现该接口:

public interface CertificateEventListener {
    
    void certificateCreated(KeyStore keyStore, String alias, X509Certificate cert);

    void certificateDeleted(KeyStore keyStore, String alias);

    void certificateSigned(KeyStore keyStore, String alias, List<X509Certificate> certificates);
}

其中共有三个方法,分别对证书的创建,删除以及签发等三个事件进行监听。


ConnectionManager为连接管理接口,其内部定义了一些用来管理服务器连接所需用到的方法以及一些默认端口。

public interface ConnectionManager {

    final int DEFAULT_PORT = 5222;
 
    final int DEFAULT_SSL_PORT = 5223;
   
    final int DEFAULT_COMPONENT_PORT = 5275;
    
    final int DEFAULT_SERVER_PORT = 5269;
    
    final int DEFAULT_MULTIPLEX_PORT = 5262;
 
    public Collection<ServerPort> getPorts();

    public SocketReader createSocketReader(Socket socket, boolean isSecure, ServerPort serverPort,
            boolean useBlockingMode) throws IOException;


    public void enableClientListener(boolean enabled);

    public boolean isClientListenerEnabled();

    public void enableClientSSLListener(boolean enabled);

    public boolean isClientSSLListenerEnabled();

    public void enableComponentListener(boolean enabled);

    public boolean isComponentListenerEnabled();

    public void enableServerListener(boolean enabled);

    public boolean isServerListenerEnabled();

    public void enableConnectionManagerListener(boolean enabled);

    public boolean isConnectionManagerListenerEnabled();

    public void setClientListenerPort(int port);

    public int getClientListenerPort();

    public void setClientSSLListenerPort(int port);

    public int getClientSSLListenerPort();

    public void setComponentListenerPort(int port);

    public int getComponentListenerPort();

    public void setServerListenerPort(int port);

    public int getServerListenerPort();

    public void setConnectionManagerListenerPort(int port);

    public int getConnectionManagerListenerPort();
}


上面接口中列举了大量的方法,它们的具体用途留待ConnectionManagerImpl 中进行详细学习。


下面学习ConnectionManagerImpl 模块,由于该类的代码量较大,所以按着方法依次进行学习。

首先来看其对于CertificateEventListener接口中方法的具体实现:

public void certificateCreated(KeyStore keyStore, String alias, X509Certificate cert) {
        restartClientSSLListeners();
    }

    public void certificateDeleted(KeyStore keyStore, String alias) {
        restartClientSSLListeners();
    }

    public void certificateSigned(KeyStore keyStore, String alias, List<X509Certificate> certificates) {
        restartClientSSLListeners();
    }
可以看出针对三类证书事件,ConnectionManagerImpl 模块均调用了restartClientSSLListeners函数,查看该函数源码发现其在内部调用了

stopClientSSLListeners();
createClientSSLListeners();
startClientSSLListeners(localIPAddress);
这三个函数将在后面讲到start函数时在进行相应的学习。

接下来学习模块的初始化及启动,首先来看initialize函数,该函数重载了父类BasicModule中的同名函数。当服务器启动时,会调用该函数初始化该模块:

public void initialize(XMPPServer server) {
        super.initialize(server);
        serverName = server.getServerInfo().getXMPPDomain();
        router = server.getPacketRouter();
        routingTable = server.getRoutingTable();
        deliverer = server.getPacketDeliverer();
        sessionManager = server.getSessionManager();
        // Check if we need to configure MINA to use Direct or Heap Buffers
        // Note: It has been reported that heap buffers are 50% faster than direct buffers
        if (JiveGlobals.getBooleanProperty("xmpp.socket.heapBuffer", true)) {
            ByteBuffer.setUseDirectBuffers(false);
            ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
        }
    }
在其内部,主要对模块内部的一些成员变量进行初始化,并确定使用堆缓冲还是直接缓冲。
模块在初始化完成之后,服务器会调用start正式启动模块:

public void start() {
        super.start();
        createListeners();
        startListeners();
        SocketSendingTracker.getInstance().start();
        CertificateManager.addListener(this);
    }

可以看出,函数中的最后一句将本模块加入了CertificateManager中,当证书事件发生时,本模块会收到通知,并调用相应的函数。


首先来看看createListeners函数的源码:

private synchronized void createListeners() {
        if (isSocketStarted || sessionManager == null || deliverer == null || router == null || serverName == null) {
            return;
        }
        // Create the port listener for s2s communication
        createServerListener(localIPAddress);
        // Create the port listener for Connections Multiplexers
        createConnectionManagerListener();
        // Create the port listener for external components
        createComponentListener();
        // Create the port listener for clients
        createClientListeners();
        // Create the port listener for secured clients
        createClientSSLListeners();
    }
可以看到,在ConnectionManagerImpl模块中一共创建了5种监听器,来监听各种类型的连接请求。与之对应的startListeners函数中则依次启动了这些连接。下面依次进行学习。

首先来看看一个经常用到的函数buildSocketAcceptor

private SocketAcceptor buildSocketAcceptor(String name) {
        SocketAcceptor socketAcceptor;
        // Create SocketAcceptor with correct number of processors
        int ioThreads = JiveGlobals.getIntProperty("xmpp.processor.count", Runtime.getRuntime().availableProcessors());
        // Set the executor that processors will use. Note that processors will use another executor
        // for processing events (i.e. incoming traffic)
        Executor ioExecutor = new ThreadPoolExecutor(
            ioThreads + 1, ioThreads + 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() );
        socketAcceptor = new SocketAcceptor(ioThreads, ioExecutor);
        // Set that it will be possible to bind a socket if there is a connection in the timeout state
        SocketAcceptorConfig socketAcceptorConfig = socketAcceptor.getDefaultConfig();
        socketAcceptorConfig.setReuseAddress(true);
        // Set the listen backlog (queue) length. Default is 50.
        socketAcceptorConfig.setBacklog(JiveGlobals.getIntProperty("xmpp.socket.backlog", 50));

        // Set default (low level) settings for new socket connections
        SocketSessionConfig socketSessionConfig = socketAcceptorConfig.getSessionConfig();
        //socketSessionConfig.setKeepAlive();
        int receiveBuffer = JiveGlobals.getIntProperty("xmpp.socket.buffer.receive", -1);
        if (receiveBuffer > 0 ) {
            socketSessionConfig.setReceiveBufferSize(receiveBuffer);
        }
        int sendBuffer = JiveGlobals.getIntProperty("xmpp.socket.buffer.send", -1);
        if (sendBuffer > 0 ) {
            socketSessionConfig.setSendBufferSize(sendBuffer);
        }
        int linger = JiveGlobals.getIntProperty("xmpp.socket.linger", -1);
        if (linger > 0 ) {
            socketSessionConfig.setSoLinger(linger);
        }
        socketSessionConfig.setTcpNoDelay(
                JiveGlobals.getBooleanProperty("xmpp.socket.tcp-nodelay", socketSessionConfig.isTcpNoDelay()));
        if (JMXManager.isEnabled()) {
        	configureJMX(socketAcceptor, name);
        }
        return socketAcceptor;
    }
在该函数中,使用到了MINA框架,关于MINA框架,此处不再赘述。该函数中建立了一个SocketAcceptor ,用来接收client的请求,并产生I/O processor 来处理client的请求。在其中主要配置了一些参数。


ClientListeners:监听客户端的连接请求

private void createClientListeners() {
        // Start clients plain socket unless it's been disabled.
        if (isClientListenerEnabled()) {
            // Create SocketAcceptor with correct number of processors
            socketAcceptor = buildSocketAcceptor("client");
            // Customize Executor that will be used by processors to process incoming stanzas
            ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance("client");
            int eventThreads = JiveGlobals.getIntProperty("xmpp.client.processing.threads", 16);
            ThreadPoolExecutor eventExecutor = (ThreadPoolExecutor)threadModel.getExecutor();
            eventExecutor.setCorePoolSize(eventThreads + 1);
            eventExecutor.setMaximumPoolSize(eventThreads + 1);
            eventExecutor.setKeepAliveTime(60, TimeUnit.SECONDS);

            socketAcceptor.getDefaultConfig().setThreadModel(threadModel);
            // Add the XMPP codec filter
            socketAcceptor.getFilterChain().addFirst("xmpp", new ProtocolCodecFilter(new XMPPCodecFactory()));
            // Kill sessions whose outgoing queues keep growing and fail to send traffic
            socketAcceptor.getFilterChain().addAfter("xmpp", "outCap", new StalledSessionsFilter());
        }
    }

在上面的函数中,值得注意的一点是最后两行代码,分别向socketAcceptor 的FilterChain中添加了两个过滤器。其中,第一个过滤器用来解析XMPP协议。查看器代码发现,真正用来解析XMPP协议的Decoder是其中的XMPPDecoder类型的成员变量,查看XMPPDecoder源码:

public class XMPPDecoder extends CumulativeProtocolDecoder {

    @Override
	protected boolean doDecode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out)
            throws Exception {
        // Get the XML light parser from the IoSession
        XMLLightweightParser parser = (XMLLightweightParser) session.getAttribute(ConnectionHandler.XML_PARSER);
        // Parse as many stanzas as possible from the received data
        parser.read(in);

        if (parser.areThereMsgs()) {
            for (String stanza : parser.getMsgs()) {
                out.write(stanza);
            }
        }
        return !in.hasRemaining();
    }
}
其中重写了doDecode函数,在其中通过IoSession的ConnectionHandler.XML_PARSER(其值为"XML-PARSER") 属性获取XMLLightweightParser 并从输入流中读取接收到的数据并解码成xml格式的数据。

第二个过滤器StalledSessionsFilter主要是用来关闭一些 异常连接(如其外出队列持续增长,不能正常的向外发送数据),来防止内存溢出。在该过滤器中设置默认最大队列长度为50M。此长度可以修改。


当创建完ClientListeners后,接下来看看startClientListeners函数,该函数中最重要的代码如下所示:

socketAcceptor
        .bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler(serverName));
其用途是将socketAcceptor 绑定在本地某个端口上,并将其与ClientConnectionHandler相关联,然后启动socketAcceptor 来监听客户端的请求。当接收到客户端的请求或消息后,具体的操作定义在ClientConnectionHandler中。
ClientConnectionHandler继承自抽象类ConnectionHandler。而ConnectionHandler继承自 MINA框架中定义的IoHandlerAdapter。其用途主要是负责创建新的连接会话,删除会话以及将接收到的XML数据传递到合适的Handler中。

未完待续~~~~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值