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 {  

    private ConcurrentLinkedQueue<IMessage> frameBuffer = new ConcurrentLinkedQueue<IMessage>();
    String host = "127.0.0.1";
    String app = "red5test";  
    int port = 1935;  

    public RtmpClientTest() {  
        super();  
        Map<String, Object> map = makeDefaultConnectionParams(host,  
            1935, "red5test");  
        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) {   
        ObjectMap<?, ?> map = (ObjectMap<?, ?>) notify.getCall().getArguments()[0];
        String code = (String) map.get("code");
        if (StatusCodes.NS_PUBLISH_START.equals(code)) {
            IMessage message = null;
            while ((message = frameBuffer.poll()) != null) {
                this.publishStreamData(streamId, message);
            }
        } else if (StatusCodes.NS_UNPUBLISHED_SUCCESS.equals(code)) {

        }
    }  

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

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

RtmpClientTest实现的三个接口INetStreamEventHandler、IPendingServiceCallback、IEventDispatcher和回调函数有关,后面的章节会分析到。
首先来看RtmpClientTest的构造函数,其父类RTMPClient的构造函数如下

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

red5客户端使用mina框架来封装Java Nio,关于mina框架的源码分析请查看博主的mina源码分析系列文章。这里有两个handler,RTMPMinaIoHandler和mina框架有关,另一个handler就是RTMPClient自身,因为其继承自BaseRTMPClientHandler,BaseRTMPClientHandler和业务有关。
回到RtmpClientTest构造函数,接下来调用connect进行连接,connect函数实现在RTMPClient的父类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);
    }

connect函数一开始作了一些简单的设置,最后通过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函数。connect函数会使用mina框架与服务器建立连接,下一章会分析服务器如何处理客户端的连接请求。当与服务器建立完连接(TCP连接)时,根据mina框架的源码,会回调mina框架中IoHandler的处理函数,也即前面注册的RTMPMinaIoHandler的sessionCreated和sessionOpened函数,下面依次来看。

一. sessionCreated

sessionCreated的代码如下,

    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");
            if (!StringUtils.isEmpty(swfUrl)) {
                outgoingHandshake.initSwfVerification(swfUrl);
            }
        }
        session.setAttribute(RTMPConnection.RTMP_HANDLER, handler);
        handler.setConnection((RTMPConnection) conn);
    }

sessionCreated函数首先向mina框架中添加一个过滤器RTMPEIoFilter,该过滤器用来处理RTMP协议的握手过程,具体的RTMP协议可以从网上下载。sessionCreated接着创建一个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

再来看RTMPMinaIoHandler的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);
    }

这里根据从session中获得刚刚在sessionCreated中创建的OutboundHandshake,调用其generateClientRequest1函数生成第一次握手请求的数据,通过write函数发送给服务器。generateClientRequest1函数和具体的协议相关,这里就不继续往下看了。

总结一下,本章分析了如何创建一个RTMPClient并建立与服务器的TCP连接,然后发送第一次握手请求开始与服务器建立RTMP连接,下一章开始分析red5服务器端对应的连接函数。

Node-RED 是一个基于 Node.js 构建的开源流程编排工具,它具有简单易用的特点,可以帮助用户快速搭建、管理和部署流程应用。Node-RED 的源码分析是指对其代码库进行深入剖析,以便了解其内部结构和工作原理。 首先,Node-RED 的源码主要由 JavaScript 编写,大部分代码都是围绕 Node.js 运行时环境展开。其核心功能是基于事件驱动的管道式数据处理,通过流程图的方式将各种节点(Node)串联起来,形成一个数据处理流程。因此,在源码分析中,需要重点关注事件驱动机制、节点的定义与扩展、消息传递机制等方面的实现细节。 其次,Node-RED 采用了 Express 框架来搭建 Web 服务,并通过 WebSocket 实现了实时通信。在源码分析中,需要深入了解其 Web 服务的实现方式,以及与客户端的交互方式和消息传递机制。此外,还需要对其对外部插件和节点的支持机制进行分析,以便了解其扩展性和定制化能力。 最后,在源码分析中还需要深入了解 Node-RED 的核心模块以及各种节点的实现方式,比如文件操作、网络请求、数据库操作等,以及其对于不同数据格式的处理能力。同时,还需要关注其错误处理、安全机制、性能优化等方面的实现方式。 总的来说,Node-RED 的源码分析是一个复杂而全面的工作,需要对 JavaScript 和 Node.js 相关技术有深入的了解,以便更好地理解其内部结构和工作原理,为进一步的定制和扩展工作提供有力的支持。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值