red5源码分析---4
2016-05-04 15:51
330 查看
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”命令的。
相关文章推荐
- elasticsearch.yml
- ORACLE按日期分组写法
- 使用Packet Sniffer抓包和分析(z-stack协议)
- Android属性动画(一) ------ 站在巨人的肩膀上学习总结
- 蓝桥杯 蚂蚁感冒
- 联合体(union)的使用方法及其本质
- javaweb学习总结(三十)——EL函数库
- 网址的正则表达式
- http://www.ezlippi.com/blog/2014/12/c-open-project.html
- Windows驱动开发(6) - DRIVER_OBJECT结构体
- Notepad++使用心得和特色功能介绍
- 快速排序
- Hbase LSM树
- 创建自己的Cocoapods库
- TIKA元数据提取
- ZOJ 3326 An Awful Problem(模拟)
- 【辅助算法】整体二分
- 100个常用的原生JavaScript函数
- 第四章 第三节 YARN调度
- 四则运算之加减法