red5源码分析---1

red5源码分析—客户端连接

本博文开始分析red5版本1.0.7的源码,详细分析从客户端到服务器的完整流程。
red5发展到现在,可以兼容很多协议,例如rtmp、rtmpt等等。本博文只分析rtmp协议,其他协议看看以后有没有时间研究吧。
red5的服务器启动有好几种方式,standalone、tomcat、jetty等等。本文只分析standalone的启动方式。客户端也一样,本博文分析使用red5 rtmpclient作为客户端的情况。
red5 client和server的下载地址如下
https://github.com/Red5
先看一段网上很常见的使用red5的客户端代码,

public class RtmpClientTest extends RTMPClient implements INetStreamEventHandler, IPendingServiceCallback, IEventDispatcher {  

    String host = "127.0.0.1";
    String app = "chainGunSyncService";  
    int port = 1935;  

    public RtmpClientTest() {  
        super();  
        Map<String, Object> map = makeDefaultConnectionParams(host,  
            1935, "chainGunSyncService");  
        connect(host, 1935, map, this);  
    }  

    @Override  
    public void dispatchEvent(IEvent arg0) {   
    }  

    @Override  
    public void resultReceived(IPendingServiceCall call) { 
        Object result = call.getResult();  
        if (result instanceof ObjectMap) {  
            if ("connect".equals(call.getServiceMethodName())) {  
                createStream(this);  
            }  
        } else {  
            if ("createStream".equals(call.getServiceMethodName())) {  
                if (result instanceof Integer) {  
                    Integer streamIdInt = (Integer) result;  
                    // int streamId = streamIdInt.intValue(); 
                    // publish(streamId, "testgio2", "live", this); 
                    invoke("getRoomsInfo", this);  
                } else {  
                    disconnect();  
                }  
            } else if ("getRoomsInfo".equals(call.getServiceMethodName())) {  
                ArrayList<String> list = (ArrayList<String>) result;  
                for (int i = 0; i < list.size(); i++) {  
                    System.out.println(list.get(i));  
                }  
            }  
        }  
    }  

    @Override  
    public void onStreamEvent(Notify arg0) {   
    }  

    @Override  
    public void connectionOpened(RTMPConnection conn, RTMP state) {   
        super.connectionOpened(conn, state);  
    }  

    public static void main(String[] args) {  
        new RtmpClientTest();  
    }  
}

首先来看RtmpClientTest的构造函数,其父类RTMPClient的构造函数如下

    public RTMPClient() {
        ioHandler = new RTMPMinaIoHandler();
        ioHandler.setHandler(this);
    }

red5 Client使用了mina框架来封装Java Nio,关于mina框架的源码分析请查看博主的其他文章吧。这里有两个handler,RTMPMinaIoHandler暂时命名为框架handler吧,和mina框架有关,另一个handler就是RTMPClient自身,因为其继承自BaseRTMPClientHandler,暂时命名为业务handler吧。
回到RtmpClientTest构造函数,接下来调用connect进行连接,connect函数实现在刚才提到的其父类的父类BaseRTMPClientHandler中,

    public void connect(String server, int port, Map<String, Object> connectionParams, IPendingServiceCallback connectCallback) {
        connect(server, port, connectionParams, connectCallback, null);
    }

    public void connect(String server, int port, Map<String, Object> connectionParams, IPendingServiceCallback connectCallback, Object[] connectCallArguments) {
        this.connectionParams = connectionParams;
        this.connectArguments = connectCallArguments;
        if (!connectionParams.containsKey("objectEncoding")) {
            connectionParams.put("objectEncoding", 0);
        }
        this.connectCallback = connectCallback;
        startConnector(server, port);
    }

这里就是一些简单的赋值,关键是调用startConnector进行连接,startConnector定义在RTMPClient中,

    protected void startConnector(String server, int port) {
        socketConnector = new NioSocketConnector();
        socketConnector.setHandler(ioHandler);
        future = socketConnector.connect(new InetSocketAddress(server, port));
        future.addListener(new IoFutureListener<ConnectFuture>() {
            public void operationComplete(ConnectFuture future) {
                try {
                    session = future.getSession();
                } catch (Throwable e) {
                    socketConnector.dispose(false);
                    handleException(e);
                }
            }
        });
        future.awaitUninterruptibly(CONNECTOR_WORKER_TIMEOUT);
    }

这里主要构造了一个NioSocketConnector,并调用其connect函数。再往下就是mina框架要处理的事情了。当与服务器建立完连接(TCP)时,会回调mina框架中IoHandler的处理函数,也即RTMPMinaIoHandler的sessionCreated和sessionOpened函数,下面依次来看,

    public void sessionCreated(IoSession session) throws Exception {
        session.getFilterChain().addFirst("rtmpeFilter", new RTMPEIoFilter());
        RTMPMinaConnection conn = createRTMPMinaConnection();
        conn.setIoSession(session);
        session.setAttribute(RTMPConnection.RTMP_SESSION_ID, conn.getSessionId());
        OutboundHandshake outgoingHandshake = new OutboundHandshake();
        session.setAttribute(RTMPConnection.RTMP_HANDSHAKE, outgoingHandshake);
        if (enableSwfVerification) {
            String swfUrl = (String) handler.getConnectionParams().get("swfUrl");
            log.debug("SwfUrl: {}", swfUrl);
            if (!StringUtils.isEmpty(swfUrl)) {
                outgoingHandshake.initSwfVerification(swfUrl);
            }
        }
        session.setAttribute(RTMPConnection.RTMP_HANDLER, handler);
        handler.setConnection((RTMPConnection) conn);
    }

sessionCreated首先向mina框架中添加一个RTMPEIoFilter,该过滤器用来处理RTMP协议的握手过程,具体的RTMP协议可以从网上下载。接着创建一个RTMPMinaConnection并进行相应的设置,

    protected RTMPMinaConnection createRTMPMinaConnection() {
        return (RTMPMinaConnection) RTMPConnManager.getInstance().createConnection(RTMPMinaConnection.class);
    }

RTMPConnManager是一个单例,直接看其createConnection函数,

    public RTMPConnection createConnection(Class<?> connCls) {
        RTMPConnection conn = null;
        if (RTMPConnection.class.isAssignableFrom(connCls)) {
            try {
                conn = createConnectionInstance(connCls);
                connMap.put(conn.getSessionId(), conn);
            } catch (Exception ex) {

            }
        }
        return conn;
    }

    public RTMPConnection createConnectionInstance(Class<?> cls) throws Exception {
        RTMPConnection conn = null;
        if (cls == RTMPMinaConnection.class) {
            conn = (RTMPMinaConnection) cls.newInstance();
        } else if (cls == RTMPTClientConnection.class) {
            conn = (RTMPTClientConnection) cls.newInstance();
        } else {
            conn = (RTMPConnection) cls.newInstance();
        }
        conn.setMaxHandshakeTimeout(maxHandshakeTimeout);
        conn.setMaxInactivity(maxInactivity);
        conn.setPingInterval(pingInterval);

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setDaemon(true);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(executorQueueCapacity);
        executor.initialize();
        conn.setExecutor(executor);
        return conn;
    }

这里就是构造了一个RTMPMinaConnection实例,设置其ThreadPoolTaskExecutor,并添加进connMap中。注意每个RTMPMinaConnection的SessionId是随机生成的。
回到sessionCreated中,接下来设置刚刚构造的RTMPMinaConnection,以及其SessionId,然后构造OutboundHandshake用于RTMP的握手,握手结束后OutboundHandshake将会从session中移除,最后设置handler和RTMPMinaConnection。
再来看sessionOpened,

    public void sessionOpened(IoSession session) throws Exception {
        super.sessionOpened(session);
        RTMPHandshake handshake = (RTMPHandshake) session.getAttribute(RTMPConnection.RTMP_HANDSHAKE);
        IoBuffer clientRequest1 = ((OutboundHandshake) handshake).generateClientRequest1();
        session.write(clientRequest1);
    }

这里根据Id从session中获得在sessionCreated中构造的OutboundHandshake,调用其generateClientRequest1函数构造第一次握手的数据,通过write函数发送给服务器。generateClientRequest1函数和具体的协议相关,这里就不继续往下看了。
下一章开始分析服务器端相应的连接函数。

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