您的位置:首页 > 其它

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”命令的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: