简述
- 在accept一个链接后,创建对应的SrsRtmpConn。
- SrsRtmpConn自身是一个协程的子类,运行后进行rtmp协议中的handshake、connect、create stream。并且判断是publish之后,创建SrsRecvThread来接受推流。
但是有一点比较奇怪的写法就是,在handshake之后,connect之前就根据发的包内容来判断是一个publish还是play。这点和我认知的rtmp协议不同,在我的认知里面,rtmp协议在create stream会发play或者push的message表示自己是一个什么样的角色,一般都是通过这个方法来判断的。
- SrsRecvThread是一个协程,运行后会开始接受message数据。根据对应message执行不同的函数,并且把message放入到SrsConsumer队列中,
- 在放入SrsConsumer的队列中后会通过条件srs_cond_signal(mw_wait),通知等待的协程可以开始消费message了
accept请求
这个是接受tcp链接的代码,rtmp的tcp监听也是在这边的。accept一个fd后,调用on_tcp_client处理这个链接。
这边有一点需要注意的是,srs的io操作大部分是state thread库函数做的。调用accept的socket是一个非阻塞式的,但是st_accept用起来像阻塞式的,实际上是一个非阻塞式的。
srs_error_t SrsTcpListener::cycle()
{
srs_error_t err = srs_success;
while (true) {
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "tcp listener");
}
/*接受一个链接*/
srs_netfd_t fd = srs_accept(lfd, NULL, NULL, SRS_UTIME_NO_TIMEOUT);
if(fd == NULL){
return srs_error_new(ERROR_SOCKET_ACCEPT, "accept at fd=%d", srs_netfd_fileno(lfd));
}
if ((err = srs_fd_closeexec(srs_netfd_fileno(fd))) != srs_success) {
return srs_error_wrap(err, "set closeexec");
}
/*调用处理函数*/
if ((err = handler->on_tcp_client(fd)) != srs_success) {
return srs_error_wrap(err, "handle fd=%d", srs_netfd_fileno(fd));
}
}
return err;
}
创建SrsRtmpConn
on_tcp_client最后调用会调用fd2con,将fd生成对应的SrsRtmpConn对像。
srs_error_t SrsServer::fd2conn(SrsListenerType type, srs_netfd_t stfd, SrsConnection** pconn)
{
/*.....*/
if (type == SrsListenerRtmpStream) {
*pconn = new SrsRtmpConn(this, stfd, ip, port);
} else if (type == SrsListenerHttpApi) {
*pconn