SRS源码分析-连接建立

初始化st协程库

state-threads协程库在使用时需要初始化IO复用类型,并初始化。

srs_error_t srs_st_init()
{
    //在linux上设置为epoll()
    if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) {
        return srs_error_new(ERROR_ST_SET_EPOLL, "st enable st failed, current is %s", st_get_eventsys_name());
    }
    
    int r0 = 0;
    //初始化
    if((r0 = st_init()) != 0){
        return srs_error_new(ERROR_ST_INITIALIZE, "st initialize failed, r0=%d", r0);
    }
    srs_trace("st_init success, use %s", st_get_eventsys_name());
    
    return srs_success;
}

初始化signal

在使用state-threads时需要将信号转化为IO,并创建一个协程处理信号IO。

  1. run_master中调用svr->initialize_signal(),初始化信号
  • 调用SrsSignalManager::initialize(), 创建pipe
  1. svr->register_signal()注册信号
  • 调用SrsSignalManager::start():注册信号并启动信号监听的协程
  • 最终执行SrsSignalManager::cycle()监听
  • SrsSignalManager::cycle()函数中,循环执行监听操作,调用SrsServer::on_signal
  1. SrsServer::on_signal对每一种信号检测,如果信号发生,设置相应的bool变量为true
  2. SrsServer::do_cycle()中检查信号,并处理

监听客户端请求

listen函数监听客户端的连接,包括rtmp, http api, http stream, stream caster,并启动连接管理的协程。

监听rtmp流
//监听rtmp流
srs_error_t SrsServer::listen_rtmp()
{
    srs_error_t err = srs_success;
    
    //读取配置文件中的端口列表
    std::vector<std::string> ip_ports = _srs_config->get_listens();
    srs_assert((int)ip_ports.size() > 0);
    //先关闭rtmp相关的监听
    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);
        //调用SrsBufferListener的listen
        if ((err = listener->listen(ip, port)) != srs_success) {
            srs_error_wrap(err, "rtmp listen %s:%d", ip.c_str(), port);
        }
    }
    
    return err;
}

listern_rtmp调用调用SrsBufferListener的listen监听

//监听
srs_error_t SrsBufferListener::listen(string i, int p)
{
    srs_error_t err = srs_success;
    
    ip = i;
    port = p;
    
    srs_freep(listener);
    //创建一个TCP监听
    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;
}

SrsBufferListener是一个Listerner的缓冲类,在listern中创建了一个TCPListener,并调用其listen方法。

//监听
srs_error_t SrsBufferListener::listen(string i, int p)
{
    srs_error_t err = srs_success;
    
    ip = i;
    port = p;
    
    srs_freep(listener);
    //创建一个TCP监听
    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;
}

SrsTcpListener类进行实际的监听,通过socket->bind->listen创建监听的fd,并将fd注册到st库上,之后fd上的事件都有st库监听并处理。创建tcp协程,用于处理连接,协程启动,并进入cycle()函数。cycle()函数用于处理客户端连接

//rtmp tcp监听
srs_error_t SrsTcpListener::listen()
{
    srs_error_t err = srs_success;
    
    char sport[8];
    snprintf(sport, sizeof(sport), "%d", port);
    
    addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_NUMERICHOST;
    
    addrinfo* r = NULL;
    SrsAutoFree(addrinfo, r);
    if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) {
        return srs_error_new(ERROR_SYSTEM_IP_INVALID, "get address info");
    }
    //1. 创建socket
    if ((_fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) {
        return srs_error_new(ERROR_SOCKET_CREATE, "create socket. ip=%s, port=%d", ip.c_str(), port);
    }

#ifdef SO_KEEPALIVE
    int tcp_keepalive = 1;
    if (setsockopt(_fd, SOL_SOCKET, SO_KEEPALIVE, &tcp_keepalive, sizeof(int)) == -1) {
        return srs_error_new(ERROR_SOCKET_SETKEEPALIVE, "setsockopt SO_KEEPALIVE[%d]error. port=%d", tcp_keepalive, port);
    }
#endif

    srs_fd_close_exec(_fd); //设置FD_CLOEXEC
    srs_socket_reuse_addr(_fd); //重复使用fd
    //2. 绑定服务器ip和端口
    if (bind(_fd, r->ai_addr, r->ai_addrlen) == -1) {
        return srs_error_new(ERROR_SOCKET_BIND, "bind socket. ep=%s:%d", ip.c_str(), port);;
    }
    //3. 在_fd上开启监听
    if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {
        return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket");
    }
    //将fd注册到st库上, 此后这个fd的所有请求都交由库处理
    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);
    //启动协程,最后进入SrsSTCoroutine::cycle()
    if ((err = trd->start()) != srs_success) {
        return srs_error_wrap(err, "start coroutine");
    }
    
    return err;
}

监听协程接受连接请求后将执行逻辑交给BufferListener处理


//监听的循环
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);
        //这个监听协程只是处理连接请求,具体的执行逻辑交给BufferListener处理
        if ((err = handler->on_tcp_client(cstfd)) != srs_success) {
            return srs_error_wrap(err, "handle fd=%d", cfd);
        }
    }
    
    return err;
}

SrsBufferListener::on_tcp_client处理连接

//处理客户端的连接
srs_error_t SrsBufferListener::on_tcp_client(srs_netfd_t stfd)
{
    //交给server接受连接
    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;
}

最终调用sever的accept_client

//server接受连接
srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
{
    srs_error_t err = srs_success;
    
    SrsConnection* conn = NULL;
    //得到连接的connection
    if ((err = fd2conn(type, stfd, &conn)) != srs_success) {
        return srs_error_wrap(err, "fd2conn");
    }
    srs_assert(conn);
    
    //conns存放所有的连接
    conns.push_back(conn);

    // 每个连接都开启一个连接的协程
    if ((err = conn->start()) != srs_success) {
        return srs_error_wrap(err, "start conn coroutine");
    }
    
    return err;
}


//连接到来的fd转为connection, 对不同类型的连接创建
srs_error_t SrsServer::fd2conn(SrsListenerType type, srs_netfd_t stfd, SrsConnection** pconn)
{
    srs_error_t err = srs_success;
    
    int fd = srs_netfd_fileno(stfd); //fd
    string ip = srs_get_peer_ip(fd); //ip
    
    if (ip.empty()) {
        return srs_error_new(ERROR_SOCKET_GET_PEER_IP, "ignore empty ip, fd=%d", fd);
    }
    
    // check connection limitation.
    int max_connections = _srs_config->get_max_connections();
    //此处handle为空
    if (handler && (err = handler->on_accept_client(max_connections, (int)conns.size())) != srs_success) {
        return srs_error_wrap(err, "drop client fd=%d, max=%d, cur=%d for err: %s",
            fd, max_connections, (int)conns.size(), srs_error_desc(err).c_str());
    }
    //如果超过了连接限制,直接拒绝连接
    if ((int)conns.size() >= max_connections) {
        return srs_error_new(ERROR_EXCEED_CONNECTIONS,
            "drop fd=%d, max=%d, cur=%d for exceed connection limits",
            fd, max_connections, (int)conns.size());
    }
    
    if (true) {
        int val;
        if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
            return srs_error_new(ERROR_SYSTEM_PID_GET_FILE_INFO, "fnctl F_GETFD error! fd=%d", fd);
        }
        val |= FD_CLOEXEC;
        if (fcntl(fd, F_SETFD, val) < 0) {
            return srs_error_new(ERROR_SYSTEM_PID_SET_FILE_INFO, "fcntl F_SETFD error! fd=%d", fd);
        }
    }
    
    if (type == SrsListenerRtmpStream) {
        *pconn = new SrsRtmpConn(this, stfd, ip); //创建rtmp连接
    } else if (type == SrsListenerHttpApi) {
        *pconn = new SrsHttpApi(this, stfd, http_api_mux, ip);
    } else if (type == SrsListenerHttpStream) {
        *pconn = new SrsResponseOnlyHttpConn(this, stfd, http_server, ip);
    } else {
        srs_warn("close for no service handler. fd=%d, ip=%s", fd, ip.c_str());
        srs_close_stfd(stfd);
        return err;
    }
    
    return err;
}

SrsConnection类用于处理连接,每一个连接都有一个connnection协程处理。

//连接协程处理连接
srs_error_t SrsConnection::start()
{
    srs_error_t err = srs_success;
    //将整个连接抽象,初始化到skt上
    if ((err = skt->initialize(stfd)) != srs_success) {
        return srs_error_wrap(err, "init socket");
    }

    if ((err = trd->start()) != srs_success) {
        return srs_error_wrap(err, "coroutine");
    }

    return err;
}

//协程调用的函数,转到do_cycle()
srs_error_t SrsConnection::cycle()
{
    //SrsRtmpConn::do_cycle
    srs_error_t err = do_cycle(); //连接处理
    
    // Notify manager to remove it.
    manager->remove(this); //移除通知
    
    // success.
    if (err == srs_success) {
        srs_trace("client finished.");
        return err;
    }
    
    if (srs_is_client_gracefully_close(srs_error_code(err))) {
        srs_warn("client disconnect peer. ret=%d", srs_error_code(err));
    } else {
        srs_error("connect error %s", srs_error_desc(err).c_str());
    }
    
    srs_freep(err);
    return srs_success;
}

根据不同的连接调用不同do_cycle(), RTMP的连接处理

// rtmp连接最终调用这个do_cycle()
srs_error_t SrsRtmpConn::do_cycle()
{
    srs_error_t err = srs_success;
    
    srs_trace("RTMP client ip=%s, fd=%d", ip.c_str(), srs_netfd_fileno(stfd));
        
    rtmp->set_recv_timeout(SRS_CONSTS_RTMP_TMMS); //设置接收超时时间
    rtmp->set_send_timeout(SRS_CONSTS_RTMP_TMMS); //设置发送超时时间
    //1. rtmp握手
    if ((err = rtmp->handshake()) != srs_success) {
        return srs_error_wrap(err, "rtmp handshake");
    }
    
    SrsRequest* req = info->req;
    //2. handshake成功后,开始接收并解析客户端发送过来的RTMP消息connect
    // 该消息中指明了客户端想要连接的 app,解析信息保存在 req 中
    if ((err = rtmp->connect_app(req)) != srs_success) {
        return srs_error_wrap(err, "rtmp connect tcUrl");
    }
    
    // set client ip to request.
    req->ip = ip;
    
    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();
        }
        
        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);
        }
    }
    //3. 服务循环
    if ((err = service_cycle()) != srs_success) {
        err = srs_error_wrap(err, "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);
    }
    
    // If client is redirect to other servers, we already logged the event.
    if (srs_error_code(err) == ERROR_CONTROL_REDIRECT) {
        srs_error_reset(err);
    }
    
    return err;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值