openfire源码分析---4

ConnectionManagerImpl源码分析

openfire使用的是mina框架,关于mina框架的源码分析可以参考本人博客的另外几篇文章。这里转载一个mina的框架图,
这里写图片描述
如图所示,简单来说,IoService用于管理Socket的连接,IoFilterChain是一串过滤器,IoHandler用于业务逻辑处理。应用程序需要实现IoHandler接口并注册到mina框架中。
下面来看ConnectionManagerImpl模块,由第三章的分析知道,每个模块被调用了三个函数,一个是构造函数,一个是initialize函数,一个是start函数。首先看其构造函数,

    public ConnectionManagerImpl() {
        super("Connection Manager");
        ports = new ArrayList<ServerPort>(4);
    }

该构造函数没有实质性内容,主要是设置了模块名称Connection Manager,并初始化ports。

initialize()

    public void initialize(XMPPServer server) {
        super.initialize(server);
        serverName = server.getServerInfo().getXMPPDomain();
        router = server.getPacketRouter();
        routingTable = server.getRoutingTable();
        deliverer = server.getPacketDeliverer();
        sessionManager = server.getSessionManager();
        if (JiveGlobals.getBooleanProperty("xmpp.socket.heapBuffer", true)) {
            IoBuffer.setUseDirectBuffer(false);
            IoBuffer.setAllocator(new SimpleBufferAllocator());
        }
    }

这里也没有特别的地方,主要是一些成员变量的设置和缓存的设置。

start()

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

这里的CertificateManager用来监听ssl的相关时间,下面主要分析另外3个函数,createListeners、startListeners和SocketSendingTracker.getInstance().start()。

createListeners()

    private synchronized void createListeners() {
        if (isSocketStarted || sessionManager == null || deliverer == null || router == null || serverName == null) {
            return;
        }
        createServerListener(localIPAddress);
        createConnectionManagerListener();
        createComponentListener();
        createClientListeners();
        createClientSSLListeners();
    }

这里第一个if里,由于是第一次进入该函数,isSocketStarted 为false,因此进入下面的函数。这里调用不同的create函数创建服务器端Socket,本文重点分析createClientListeners,该函数创建的服务器端Socket用于处理客户端的连接。createClientListeners就定义在ConnectionManagerImpl中,

    private void createClientListeners() {
        if (isClientListenerEnabled()) {
            socketAcceptor = buildSocketAcceptor(CLIENT_SOCKET_ACCEPTOR_NAME);
            int maxPoolSize = JiveGlobals.getIntProperty(ConnectionSettings.Client.MAX_THREADS, 16);
            ExecutorFilter executorFilter = new ExecutorFilter(getCorePoolSize(maxPoolSize), maxPoolSize, 60, TimeUnit.SECONDS);
            ThreadPoolExecutor eventExecutor = (ThreadPoolExecutor)executorFilter.getExecutor();
            ThreadFactory threadFactory = eventExecutor.getThreadFactory();
            threadFactory = new DelegatingThreadFactory("C2S-Thread-", threadFactory);
            eventExecutor.setThreadFactory(threadFactory);

            socketAcceptor.getFilterChain().addFirst(EXECUTOR_FILTER_NAME, executorFilter);
            socketAcceptor.getFilterChain().addAfter(EXECUTOR_FILTER_NAME, XMPP_CODEC_FILTER_NAME, new ProtocolCodecFilter(new XMPPCodecFactory()));
            socketAcceptor.getFilterChain().addAfter(XMPP_CODEC_FILTER_NAME, CAPACITY_FILTER_NAME, new StalledSessionsFilter());
            int maxBufferSize = JiveGlobals.getIntProperty(ConnectionSettings.Client.MAX_READ_BUFFER, 10 * MB);
            socketAcceptor.getSessionConfig().setMaxReadBufferSize(maxBufferSize);
        }
    }

首先通过buildSocketAcceptor创建mina框架中的NioSocketAcceptor,定义在ConnectionManagerImpl中

    private NioSocketAcceptor buildSocketAcceptor(String name) {
        NioSocketAcceptor socketAcceptor;
        int processorCount = JiveGlobals.getIntProperty("xmpp.processor.count", Runtime.getRuntime().availableProcessors());
        socketAcceptor = new NioSocketAcceptor(processorCount);

        socketAcceptor.setReuseAddress(true);
        socketAcceptor.setBacklog(JiveGlobals.getIntProperty("xmpp.socket.backlog", 50));
        SocketSessionConfig socketSessionConfig = socketAcceptor.getSessionConfig();
        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;
    }

简单来说,这里就是构造了一个NioSocketAcceptor,进行相应的设置,configureJMX里面配置JMX(Java Management Extensions),JMX用来管理和监视java应用程序,本文不分析它。
回到createClientListeners函数中,接下来构造3个filter,ExecutorFilter、ProtocolCodecFilter和StalledSessionsFilter并将它们添加到NioSocketAcceptor中,其中,在构造ExecutorFilter时,创建了DelegatingThreadFactory用于创建线程,最后就是继续设置NioSocketAcceptor。下一章会分析刚才添加的3个filter的源码,这里继续往下看。

startListeners

    private synchronized void startListeners() {

        isSocketStarted = true;
        localIPAddress = InetAddress.getLocalHost().getHostAddress();

        startServerListener();
        startConnectionManagerListener(localIPAddress);
        startComponentListener();
        startClientListeners(localIPAddress);
        startClientSSLListeners(localIPAddress);
        startHTTPBindListeners();
    }

这里的代码删掉了插件相关的代码,然后调用各个函数启动Socket,这里主要看startClientListeners,

    private void startClientListeners(String localIPAddress) {

        if (isClientListenerEnabled()) {
            int port = getClientListenerPort();
            try {
                String interfaceName = JiveGlobals.getXMLProperty("network.interface");
                InetAddress bindInterface = null;
                if (interfaceName != null) {
                    if (interfaceName.trim().length() > 0) {
                        bindInterface = InetAddress.getByName(interfaceName);
                    }
                }
                socketAcceptor.setHandler(new ClientConnectionHandler(serverName));
                socketAcceptor.bind(new InetSocketAddress(bindInterface, port));

                ports.add(new ServerPort(port, serverName, localIPAddress, false, null, ServerPort.Type.client));
            }
            catch (Exception e) {

            }
        }
    }

这里主要做了两件事,一是创建了ClientConnectionHandler并将其添加到socketAcceptor中,ClientConnectionHandler包含了处理客户端请求的主要逻辑代码,下一章再来分析;二是调用socketAcceptor的bind函数构造服务器端Socket并进行监听。setHandler和bind函数请参考本博客《mina框架源码分析》。

SocketSendingTracker.getInstance().start()

SocketSendingTracker的构造函数为空函数,因此这里直接看start函数,

    public void start() {
        shutdown = false;
        checkingThread = new Thread("SocketSendingTracker") {
            @Override
            public void run() {
                while (!shutdown) {
                    checkHealth();
                    synchronized (this) {
                        try {
                            wait(10000);
                        }
                        catch (InterruptedException e) {
                        }
                    }
                }
            }
        };
        checkingThread.setDaemon(true);
        checkingThread.start();
    }

该线程每隔10秒调用checkHealth检查连接的Socket的状态,如下

    private void checkHealth() {
        for (SocketConnection connection : SocketConnection.getInstances()) {
            connection.checkHealth();
        }
    }

这里获取每个连接的Socket并调用其checkHealth,checkHealth是管理客户端Socket连接的核心函数,定义在SocketConnection中,

    boolean checkHealth() {
        long writeTimestamp = writeStarted;
        if (writeTimestamp > -1 && System.currentTimeMillis() - writeTimestamp >
                JiveGlobals.getIntProperty("xmpp.session.sending-limit", 60000)) {
            forceClose();
            return true;
        }
        else {
            if (idleTimeout > -1 && socketReader != null &&
                    System.currentTimeMillis() - socketReader.getLastActive() > idleTimeout) {
                forceClose();
                return true;
            }
        }
        return false;
    }

checkHealth做了两件事情,如果某个Socket发送数据的事件大于60秒,或者长时间处于idle状态(表示长时间没有接收到客户端发来的心跳数据包),就调用forceClose将其关闭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值