SRS 代码分析【RTMP连接请求响应】

服务器启动时调用rtmp端口的监听过程如下:

run_master()-->SrsServer::listen()--->SrsServer::listen_rtmp()
 

listen_rtmp服务端口监听流程如下:

1).获取配置文件中设定的端口列表 _srs_config->get_listens()

2).释放掉已经监听rtmp端口 close_listeners(SrsListenerRtmpStream)

3).根据端口列表创建SrsListener实例,并启动监听listener->listen(ip, port))

srs_error_t SrsServer::listen_rtmp()
{
    srs_error_t err = srs_success;
    
    // stream service port.
    std::vector<std::string> ip_ports = _srs_config->get_listens();
    srs_assert((int)ip_ports.size() > 0);
    
    close_listeners(SrsListenerRtmpStream);
    
    for (int i = 0; i < (int)ip_ports.size(); i++) {
        SrsListener* listener = new SrsBufferListener(this, SrsListenerRtmpStream);
        listeners.push_back(listener);
        
        std::string ip;
        int port;
        srs_parse_endpoint(ip_ports[i], ip, port);
        
        if ((err = listener->listen(ip, port)) != srs_success) {
            srs_error_wrap(err, "rtmp listen %s:%d", ip.c_str(), port);
        }
    }
    
    return err;
}
4). SrsBufferListener::listen()中创建SrsTcpListener的实例并启动监听listener->listen()

srs_error_t SrsBufferListener::listen(string i, int p)
{
    srs_error_t err = srs_success;
    
    ip = i;
    port = p;
    
    srs_freep(listener);
    listener = new SrsTcpListener(this, ip, port);
    
    if ((err = listener->listen()) != srs_success) {
        return srs_error_wrap(err, "buffered tcp listen");
    }
    
    string v = srs_listener_type2string(type);
    srs_trace("%s listen at tcp://%s:%d, fd=%d", v.c_str(), ip.c_str(), port, listener->fd());
    
    return err;
}

5).SrsTcpListener::listen()中绑定监听的端口,开启监听,创建SrsSTCoroutine协程实例,开启协程。

srs_error_t SrsTcpListener::listen()
{
    srs_error_t err = srs_success;
    
    if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        return srs_error_new(ERROR_SOCKET_CREATE, "create socket");
    }
    
    srs_fd_close_exec(_fd);
    srs_socket_reuse_addr(_fd);
    
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
        return srs_error_new(ERROR_SOCKET_BIND, "bind socket");
    }
    
    if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {
        return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket");
    }
    
    if ((_stfd = srs_netfd_open_socket(_fd)) == NULL){
        return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open socket");
    }
    
    srs_freep(trd);
    trd = new SrsSTCoroutine("tcp", this);
    if ((err = trd->start()) != srs_success) {
        return srs_error_wrap(err, "start coroutine");
    }
    
    return err;
}

6).SrsSTCoroutine::start()中调用st_thread_create来创建协程

srs_error_t SrsSTCoroutine::start()
{
    ......
    
    if((trd = (srs_thread_t)st_thread_create(pfn, this, 1, 0)) == NULL){
        err = srs_error_new(ERROR_ST_CREATE_CYCLE_THREAD, "create failed");
        
        srs_freep(trd_err);
        trd_err = srs_error_copy(err);
        
        return err;
    }
    
    started = true;

    return err;
}

其中pfn定义如下,pfn传入的参数this 是SrsSTCoroutine的实例

void* SrsSTCoroutine::pfn(void* arg)
{
    SrsSTCoroutine* p = (SrsSTCoroutine*)arg;
    void* res = (void*)p->cycle();
    return res;
}

pfn中会调用SrsSTCoroutine的cycle函数,函数定义如下:

srs_error_t SrsSTCoroutine::cycle()
{
    ......
    
    srs_error_t err = handler->cycle();
    if (err != srs_success) {
        return srs_error_wrap(err, "coroutine cycle");
    }
    
    return err;
}


SrsSTCoroutine::cycle()函数中会调用handler->cycle(),handler是在构造函数中赋初值的。

SrsSTCoroutine::SrsSTCoroutine(const string& n, ISrsCoroutineHandler* h, int cid)
{
    name = n;
    handler = h;
    context = cid;
    trd = NULL;
    trd_err = srs_success;
    started = interrupted = disposed = false;
}


SrsSTCoroutine对象是在SrsTcpListener::listen()进行创建的,并把SrsTcpListener对象传递给handler(SrsTcpListener是ISrsCoroutineHandler的子类)

srs_error_t SrsTcpListener::listen()
{
    ......
    trd = new SrsSTCoroutine("tcp", this);
    if ((err = trd->start()) != srs_success) {
        return srs_error_wrap(err, "start coroutine");
    }
}

因此,SrsSTCoroutine::cycle()->handler->cycle()最终调用SrsTcpListener::cycle(),SrsTcpListener::cycle()在while循环中调用srs_accept()阻塞等待连接请求的到来,当有连接到来时将获取连接的fd,接着调用handler->on_tcp_client().

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 cstfd = srs_accept(_stfd, NULL, NULL, SRS_UTIME_NO_TIMEOUT);
        if(cstfd == NULL){
            return srs_error_new(ERROR_SOCKET_CREATE, "accept failed");
        }
        
        int cfd = srs_netfd_fileno(cstfd);
        srs_fd_close_exec(cfd);
        
        if ((err = handler->on_tcp_client(cstfd)) != srs_success) {
            return srs_error_wrap(err, "handle fd=%d", cfd);
        }
    }
    
    return err;
}


SrsTcpListener中的handler是在构造函数中赋值的,代码如下

SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)
{
    handler = h;
    ip = i;
    port = p;
    
    _fd = -1;
    _stfd = NULL;
    
    trd = new SrsDummyCoroutine();
}


SrsTcpListener是在SrsBufferListener::listen()中创建的,并把SrsBufferListener对象作为参数传给handler(SrsBufferListener是ISrsTcpHandler的子类)

srs_error_t SrsBufferListener::listen(string i, int p)
{
   ......
   listener = new SrsTcpListener(this, ip, port);
    
    if ((err = listener->listen()) != srs_success) {
        return srs_error_wrap(err, "buffered tcp listen");
    }
}



因此,handler->on_tcp_client()最终调用SrsBufferListener::on_tcp_client(),代码如下:

srs_error_t SrsBufferListener::on_tcp_client(srs_netfd_t stfd)
{
    srs_error_t err = server->accept_client(type, stfd);
    if (err != srs_success) {
        srs_warn("accept client failed, err is %s", srs_error_desc(err).c_str());
        srs_freep(err);
    }
    
    return srs_success;
}

SrsBufferListener::on_tcp_client调用server->accept_client来处理客户端连接请求,server成员变量是SrsServer的实例,最终调用SrsServer::accept_client,代码如下:

srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
{
    srs_error_t err = srs_success;
    
    SrsConnection* conn = NULL;
    
    if ((err = fd2conn(type, stfd, &conn)) != srs_success) {
        return srs_error_wrap(err, "fd2conn");
    }
    srs_assert(conn);
    
    // directly enqueue, the cycle thread will remove the client.
    conns.push_back(conn);
    
    // cycle will start process thread and when finished remove the client.
    // @remark never use the conn, for it maybe destroyed.
    if ((err = conn->start()) != srs_success) {
        return srs_error_wrap(err, "start conn coroutine");
    }
    
    return err;
}

SrsServer::accept_client调用fd2conn(type, stfd, &conn)创建一个连接对象SrsRtmpConn(SrsRtmpConn是SrsConnection的子类),
SrsConnection中有个协程类型SrsSTCoroutine成员变量trd,调用过程如下:
SrsServer::accept_client--->SrsConnection::start--->SrsSTCoroutine::start-->SrsConnection::cycle--->SrsRtmpConn::do_cycle
由于SrsConnection中do_cycle是纯虚函数,实际调用的是SrsRtmpConn::do_cycle,

该函数完成rtmp握手,连接以及一些检查,最终进入到service_cycle,至此rtmp连接已经建立。具体代码如下:

srs_error_t SrsRtmpConn::do_cycle()
{
    int ret = ERROR_SUCCESS;
    srs_error_t err = srs_success;
    
    srs_trace("RTMP client ip=%s, fd=%d", ip.c_str(), srs_netfd_fileno(stfd));
    
    // notify kafka cluster.
#ifdef SRS_AUTO_KAFKA
    if ((ret = _srs_kafka->on_client(srs_id(), SrsListenerRtmpStream, ip)) != ERROR_SUCCESS) {
        return srs_error_new(ret, "kafka on client");
    }
#endif
    
    rtmp->set_recv_timeout(SRS_CONSTS_RTMP_TMMS);
    rtmp->set_send_timeout(SRS_CONSTS_RTMP_TMMS);
    
    if ((ret = rtmp->handshake()) != ERROR_SUCCESS) {
        return srs_error_new(ret, "rtmp handshake");
    }
    
    SrsRequest* req = info->req;
    if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) {
        return srs_error_new(ret, "rtmp connect tcUrl");
    }
    
    // set client ip to request.
    req->ip = ip;
    
    // discovery vhost, resolve the vhost from config
    SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost);
    if (parsed_vhost) {
        req->vhost = parsed_vhost->arg0();
    }
    
    srs_info("discovery app success. schema=%s, vhost=%s, port=%d, app=%s",
        req->schema.c_str(), req->vhost.c_str(), req->port, req->app.c_str());
    
    if (req->schema.empty() || req->vhost.empty() || req->port == 0 || req->app.empty()) {
        return srs_error_new(ERROR_RTMP_REQ_TCURL, "discovery tcUrl failed, tcUrl=%s, schema=%s, vhost=%s, port=%d, app=%s",
            req->tcUrl.c_str(), req->schema.c_str(), req->vhost.c_str(), req->port, req->app.c_str());
    }
    
    // check vhost, allow default vhost.
    if ((ret = check_vhost(true)) != ERROR_SUCCESS) {
        return srs_error_new(ret, "check vhost");
    }
    
    srs_trace("connect app, tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%d, app=%s, args=%s",
        req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(),
        req->schema.c_str(), req->vhost.c_str(), req->port,
        req->app.c_str(), (req->args? "(obj)":"null"));
    
    // show client identity
    if(req->args) {
        std::string srs_version;
        std::string srs_server_ip;
        int srs_pid = 0;
        int srs_id = 0;
        
        SrsAmf0Any* prop = NULL;
        if ((prop = req->args->ensure_property_string("srs_version")) != NULL) {
            srs_version = prop->to_str();
        }
        if ((prop = req->args->ensure_property_string("srs_server_ip")) != NULL) {
            srs_server_ip = prop->to_str();
        }
        if ((prop = req->args->ensure_property_number("srs_pid")) != NULL) {
            srs_pid = (int)prop->to_number();
        }
        if ((prop = req->args->ensure_property_number("srs_id")) != NULL) {
            srs_id = (int)prop->to_number();
        }
        
        srs_info("edge-srs ip=%s, version=%s, pid=%d, id=%d",
            srs_server_ip.c_str(), srs_version.c_str(), srs_pid, srs_id);
        if (srs_pid > 0) {
            srs_trace("edge-srs ip=%s, version=%s, pid=%d, id=%d",
                srs_server_ip.c_str(), srs_version.c_str(), srs_pid, srs_id);
        }
    }
    
    if ((ret = service_cycle()) != ERROR_SUCCESS) {
        err = srs_error_new(ret, "service cycle");
    }
    
    srs_error_t r0 = srs_success;
    if ((r0 = on_disconnect()) != srs_success) {
        err = srs_error_wrap(err, "on disconnect %s", srs_error_desc(r0).c_str());
        srs_freep(r0);
    }
    
    return err;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值