red5源码分析---2

red5源码分析—服务器连接

red5服务器端也采用了mina框架进行底层Socket的封装。red5使用Spring管理相关的bean,下面简单说明一下red5 standalone的启动流程。
main函数在org.red5.server.Bootstrap中,该类加载org.red5.server.Launcher,Launcher通过Spring解析red5.xml文件,red5.xml文件会继续根据red5-common.xml和red5-core.xml创建相应的bean,并根据red5.globals文件创建一个GlobalScope,后面会提到。
本文从red5-core.xml文件中构造的RTMPMinaTransport说起,

    <bean id="rtmpTransport" class="org.red5.server.net.rtmp.RTMPMinaTransport" init-method="start" destroy-method="stop">
        <property name="ioHandler" ref="rtmpMinaIoHandler" />
        <property name="addresses">
            <list>
                <value>${rtmp.host}:${rtmp.port}</value>
            </list>
        </property>
        <property name="ioThreads" value="${rtmp.io_threads}" />
        <property name="sendBufferSize" value="${rtmp.send_buffer_size}" />
        <property name="receiveBufferSize" value="${rtmp.receive_buffer_size}" />
        <property name="trafficClass" value="${rtmp.traffic_class}" />
        <property name="backlog" value="${rtmp.backlog}" />
        <property name="tcpNoDelay" value="${rtmp.tcp_nodelay}" />
        <property name="keepAlive" value="${rtmp.tcp_keepalive}" />
        <property name="thoughputCalcInterval" value="${rtmp.thoughput_calc_interval}" />
        <property name="enableDefaultAcceptor" value="${rtmp.default_acceptor}" />
        <property name="initialPoolSize" value="${rtmp.initial_pool_size}" />
        <property name="maxPoolSize" value="${rtmp.max_pool_size}" />
        <property name="maxProcessorPoolSize" value="${rtmp.max_processor_pool_size}" />
        <property name="executorKeepAliveTime" value="${rtmp.executor_keepalive_time}" />
        <property name="minaPollInterval" value="${jmx.mina.poll.interval}" />
        <property name="enableMinaMonitor" value="${jmx.mina.monitor.enable}" />
        <property name="enableMinaLogFilter" value="${mina.logfilter.enable}" />
    </bean>

根据bean的配置,spring会调用RTMPMinaTransport的start函数进行初始化,

    public void start() throws Exception {
        initIOHandler();
        IoBuffer.setUseDirectBuffer(!useHeapBuffers);
        if (useHeapBuffers) {
            IoBuffer.setAllocator(new SimpleBufferAllocator());
        }
        if (enableDefaultAcceptor) {
            acceptor = new NioSocketAcceptor(ioThreads);
        } else {
            SimpleIoProcessorPool<NioSession> pool = new SimpleIoProcessorPool<NioSession>(NioProcessor.class, maxProcessorPoolSize);
            executor = new ThreadPoolExecutor(initialPoolSize, maxPoolSize, executorKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(Short.MAX_VALUE));
            acceptor = new NioSocketAcceptor(executor, pool);
        }
        if (enableMinaLogFilter) {
            DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
            LoggingFilter logFilter = new LoggingFilter(RTMPMinaTransport.class);
            chain.addLast("logger", logFilter);
        }
        acceptor.setCloseOnDeactivation(true);
        acceptor.setHandler(ioHandler);
        acceptor.setBacklog(backlog);
        SocketSessionConfig sessionConf = acceptor.getSessionConfig();
        sessionConf.setReuseAddress(true);
        sessionConf.setTcpNoDelay(tcpNoDelay);
        sessionConf.setSendBufferSize(sendBufferSize);
        sessionConf.setReceiveBufferSize(receiveBufferSize);
        sessionConf.setMaxReadBufferSize(receiveBufferSize);
        sessionConf.setThroughputCalculationInterval(thoughputCalcInterval);
        sessionConf.setReaderIdleTime(readerIdleTime);
        sessionConf.setKeepAlive(keepAlive);
        if (trafficClass == -1) {

        } else {
            sessionConf.setTrafficClass(trafficClass);
        }
        acceptor.setReuseAddress(true);
        try {
            Set<InetSocketAddress> socketAddresses = new HashSet<InetSocketAddress>();
            for (String addr : addresses) {
                if (addr.indexOf(':') != -1) {
                    String[] parts = addr.split(":");
                    socketAddresses.add(new InetSocketAddress(parts[0], Integer.valueOf(parts[1])));
                } else {
                    socketAddresses.add(new InetSocketAddress(addr, 1935));
                }
            }
            acceptor.bind(socketAddresses);
            String cName = this.getClass().getName();
            if (cName.indexOf('.') != -1) {
                cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", "");
            }
            if (enableMinaMonitor) {
                stats = new IoServiceStatistics((AbstractIoService) acceptor);
                stats.setThroughputCalculationInterval(minaPollInterval);
                MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
                try {
                    serviceManagerObjectName = new ObjectName("org.red5.server:type=RTMPMinaTransport");
                    mbs.registerMBean(new StandardMBean(this, RTMPMinaTransportMXBean.class, true), serviceManagerObjectName);
                } catch (Exception e) {

                }
            }
        } catch (Exception e) {

        }
    }

这段代码虽然较长,但其实是mina框架的初始化,initIOHandler用于初始化mina框架中的handler,但根据red5-core.xml,其已经被初始化为RTMPMinaIoHandler,并设置其handler为RTMPHandler,和上一章分析类似,RTMPMinaIoHandler属于mina框架调用,RTMPHandler属于RTMP业务调用,两个handler执行的环境不同。

    <bean id="rtmpHandler" class="org.red5.server.net.rtmp.RTMPHandler">
        <property name="server" ref="red5.server" />
        <property name="statusObjectService" ref="statusObjectService" />
    </bean>

    <bean id="rtmpMinaIoHandler" class="org.red5.server.net.rtmp.RTMPMinaIoHandler">
        <property name="handler" ref="rtmpHandler" />
    </bean>

再往下设置了IoBuffer,构造NioSocketAcceptor用于监听客户端连接,并对其进行设置,然后就调用其bind开始监听了。
当有客户端连接到来时,mina框架回调RTMPMinaIoHandler的sessionCreated和sessionOpened函数,下面来看,

    public void sessionCreated(IoSession session) throws Exception {
        session.getFilterChain().addFirst("rtmpeFilter", new RTMPEIoFilter());
        RTMPMinaConnection conn = createRTMPMinaConnection();
        conn.setIoSession(session);
        conn.setHandler(handler);
        session.setAttribute(RTMPConnection.RTMP_SESSION_ID, conn.getSessionId());
        session.setAttribute(RTMPConnection.RTMP_HANDSHAKE, new InboundHandshake());
    }

首先添加了RTMPEIoFilter过滤器用于握手,然后通过createRTMPMinaConnection构造了一个RTMPMinaConnection,然后将RTMPHandler设置进去,并向session中添加InboundHandshake用于服务器端的握手。
下面来看sessionOpened,

    public void sessionOpened(IoSession session) throws Exception {
        String sessionId = (String) session.getAttribute(RTMPConnection.RTMP_SESSION_ID);
        RTMPConnManager connManager = (RTMPConnManager) RTMPConnManager.getInstance();
        session.setAttribute(RTMPConnection.RTMP_CONN_MANAGER, new WeakReference<IConnectionManager<RTMPConnection>>(connManager));
        RTMPMinaConnection conn = (RTMPMinaConnection) connManager.getConnectionBySessionId(sessionId);
        handler.connectionOpened(conn);
    }

其实这里就能很明显地看出,客户端这段代码仅仅设置了RTMPMinaConnection。而这里服务端的代码设置了整个RTMPConnManager,并根据sessionId找到该RTMPMinaConnection。
最后调用了RTMPHandler的connectionOpened函数,该函数设置了握手等待的最长时间,这里就不往下看了。

你可能感兴趣的:(源码,服务器,Red5)