red5源码分析---4

red5源码分析—服务器端握手

上一章分析了red5客户端握手的过程,这一章开始分析red5服务器端握手的过程。
和客户端的代码类似,在red5服务器端建立TCP连接之后,会执行RTMPMinaIoHandler的sessionCreated函数,在该函数中会注册RTMPEIoFilter过滤器,之后,所有的消息都会经过该过滤器,握手的消息也不例外,下面就来看该过滤器的messageReceived函数,

    public void messageReceived(NextFilter nextFilter, IoSession session, Object obj) throws Exception {
        String sessionId = (String) session.getAttribute(RTMPConnection.RTMP_SESSION_ID);
        if (sessionId != null) {
            RTMPMinaConnection conn = (RTMPMinaConnection) RTMPConnManager.getInstance().getConnectionBySessionId(sessionId);
            RTMP rtmp = conn.getState();
            final byte connectionState = conn.getStateCode();
            IoBuffer message = (IoBuffer) obj;
            InboundHandshake handshake = null;
            switch (connectionState) {
                case RTMP.STATE_CONNECT:
                    ...
                    break;
                case RTMP.STATE_HANDSHAKE:
                    ...
                    break;
                case RTMP.STATE_CONNECTED:
                    ...
                    break;
                case RTMP.STATE_ERROR:
                case RTMP.STATE_DISCONNECTING:
                case RTMP.STATE_DISCONNECTED:
                    break;
                default:
            }
        }
    }

这段代码和上一章客户端握手过程的代码类似,首先获得sessionId,然后根据该sessionId从RTMPConnManager获得RTMPMinaConnection,接着从该RTMPMinaConnection获得该连接的状态,一共有6种状态,STATE_CONNECTED表示连接完成,STATE_CONNECT表示正在连接(握手的第一状态),STATE_HANDSHAKE表示正在握手(握手的第二状态),STATE_ERROR表示发生错误,STATE_DISCONNECTING表示正在关闭连接,STATE_DISCONNECTED表示已关闭连接,下面只看前三种状态对应的处理方式。

一. 状态STATE_CONNECT

STATE_CONNECT状态是RTMPMinaConnection创建后的默认状态,表示还没开始进行RTMP握手,下面来看在这种状态下的处理方式,

    public void messageReceived(NextFilter nextFilter, IoSession session, Object obj) throws Exception {
            ...
            switch (connectionState) {
                case RTMP.STATE_CONNECT:
                    handshake = (InboundHandshake) session.getAttribute(RTMPConnection.RTMP_HANDSHAKE);
                    handshake.addBuffer(message);
                    int c0c1Size = handshake.getBufferSize();
                    if (c0c1Size >= (Constants.HANDSHAKE_SIZE + 1)) {
                        IoBuffer buf = handshake.getBufferAsIoBuffer();
                        byte connectionType = buf.get();
                        handshake.setHandshakeType(connectionType);
                        byte[] dst = new byte[Constants.HANDSHAKE_SIZE];
                        buf.get(dst);
                        rtmp.setState(RTMP.STATE_HANDSHAKE);
                        int remaining = buf.remaining();
                        if (remaining > 0) {
                            handshake.addBuffer(buf);
                            log.trace("Stored {} bytes for later decoding", remaining);
                        }
                        IoBuffer s1 = handshake.decodeClientRequest1(IoBuffer.wrap(dst));
                        if (s1 != null) {
                            session.write(s1);
                        } else {
                            conn.close();
                        }
                    }
                    break;
                case RTMP.STATE_HANDSHAKE:
                    ...
                    break;
                case RTMP.STATE_CONNECTED:
                    ...
                    break;
                case RTMP.STATE_ERROR:
                case RTMP.STATE_DISCONNECTING:
                case RTMP.STATE_DISCONNECTED:
                    break;
                default:
            }
        }
    }

InboundHandshake是在《red5源码分析—2》中当TCP连接建立后Mina框架调用sessionCreated时设置进session中的,下面的代码就和协议相关进行数据处理,如果收到了客户端的C0C1信息,就调用InboundHandshake的decodeClientRequest1方法生成第一次握手信息S1并返回给客户端,然后将RTMPMinaConnection的状态设置成STATE_HANDSHAKE。

二. 状态STATE_HANDSHAKE

STATE_HANDSHAKE状态代表第二次握手状态,进入该状态并收到客户端发来的C2消息时,就代表握手过程即将完成,下面来看

    public void messageReceived(NextFilter nextFilter, IoSession session, Object obj) throws Exception {
            ...
            switch (connectionState) {
                case RTMP.STATE_CONNECT:
                    ...
                    break;
                case RTMP.STATE_HANDSHAKE:
                    handshake = (InboundHandshake) session.getAttribute(RTMPConnection.RTMP_HANDSHAKE);
                    handshake.addBuffer(message);
                    int c2Size = handshake.getBufferSize();
                    if (c2Size >= Constants.HANDSHAKE_SIZE) {
                        IoBuffer buf = handshake.getBufferAsIoBuffer();
                        byte[] dst = new byte[Constants.HANDSHAKE_SIZE];
                        buf.get(dst);
                        if (handshake.decodeClientRequest2(IoBuffer.wrap(dst))) {
                            rtmp.setState(RTMP.STATE_CONNECTED);
                            if (handshake.useEncryption()) {
                                rtmp.setEncrypted(true);
                                session.setAttribute(RTMPConnection.RTMPE_CIPHER_IN, handshake.getCipherIn());
                                session.setAttribute(RTMPConnection.RTMPE_CIPHER_OUT, handshake.getCipherOut());
                            } 
                            session.removeAttribute(RTMPConnection.RTMP_HANDSHAKE);
                            session.getFilterChain().addAfter("rtmpeFilter", "protocolFilter", new ProtocolCodecFilter(new RTMPMinaCodecFactory()));
                            if (buf.hasRemaining()) {
                                nextFilter.messageReceived(session, buf);
                            }
                        } else {
                            conn.close();
                            break;
                        }
                    }
                    break;
                case RTMP.STATE_CONNECTED:
                    ...
                    break;
                case RTMP.STATE_ERROR:
                case RTMP.STATE_DISCONNECTING:
                case RTMP.STATE_DISCONNECTED:
                    break;
                default:
            }
        }
    }

STATE_HANDSHAKE状态对应的代码主要处理客户端发过来的C2消息,生成S2消息,将连接状态设置为STATE_CONNECTED,从session中移除InboundHandshake,节省内存,因为握手过程结束了就用不到了。

第三种状态STATE_CONNECTED

当握手过程结束后,所有发自客户端的消息就会进入该状态,

    public void messageReceived(NextFilter nextFilter, IoSession session, Object obj) throws Exception {
            ...
            switch (connectionState) {
                case RTMP.STATE_CONNECT:
                    ...
                    break;
                case RTMP.STATE_HANDSHAKE:
                    ...
                    break;
                case RTMP.STATE_CONNECTED:
                    if (!rtmp.isEncrypted()) {
                        nextFilter.messageReceived(session, message);
                    } else {
                        Cipher cipher = (Cipher) session.getAttribute(RTMPConnection.RTMPE_CIPHER_IN);
                        if (cipher != null) {
                            if (log.isDebugEnabled()) {
                                log.debug("Decrypting message: {}", message);
                            }
                            byte[] encrypted = new byte[message.remaining()];
                            message.get(encrypted);
                            message.clear();
                            message.free();
                            byte[] plain = cipher.update(encrypted);
                            IoBuffer messageDecrypted = IoBuffer.wrap(plain);
                            nextFilter.messageReceived(session, messageDecrypted);
                        }
                    }
                    break;
                case RTMP.STATE_ERROR:
                case RTMP.STATE_DISCONNECTING:
                case RTMP.STATE_DISCONNECTED:
                    break;
                default:
            }
        }
    }

在该状态下,接收到的消息有两种选择,第一种要进行加密的处理,这里就不仔细看了,如果不需要加密的处理,就直接调用nextFilter的messageReceived函数,这属于nextFilter在mina框架中最后就会调用RTMPMinaIoHandler的messageReceived函数。

分析到这里,客户端已经与服务器端建立了TCP连接,并且结束了RTMP的握手过程,但是在处理业务逻辑前,客户端和服务器还需要继续进行沟通,在《red5源码分析—3》中最后提到,客户端在握手成功后会自动向red5服务器发送”connect”命令,下一章节就开始分析服务器是如何处理”connect”命令的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值