srs代码学习(3)-链接管理

本文深入分析SRS服务器的连接管理,从accept_client函数入手,探讨SrsOneCycleThread线程类及其在处理连接请求中的应用。同时,文章将围绕RTMP协议的实现展开,包括rtmp server连接、hook机制、edge和forward功能以及统计方法,为理解SRS内部工作原理提供详细解读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上次谈到端口侦听后,如果有连接上来,会一直回调到server的accept_client函数里。下面来一步一步分析这个函数。并分析下srs的连接框架

int max_connections = _srs_config->get_max_connections();
    if ((int)conns.size() >= max_connections) {
        srs_error("exceed the max connections, drop client: "
            "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd);
            
        srs_close_stfd(client_stfd);
        
        return ret;
    }
首先检测是否达到了最大连接数。这个连接数是所有连接,包括rtmp http rtsp等的连接数。这个最大连接数可以在配置文件中配置。默认为SRS_CONF_DEFAULT_MAX_CONNECTIONS =1000

    if (true) {
        int val;
        if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
            ret = ERROR_SYSTEM_PID_GET_FILE_INFO;
            srs_error("fnctl F_GETFD error! fd=%d. ret=%#x", fd, ret);
            srs_close_stfd(client_stfd);
            return ret;
        }
        val |= FD_CLOEXEC;
        if (fcntl(fd, F_SETFD, val) < 0) {
            ret = ERROR_SYSTEM_PID_SET_FILE_INFO;
            srs_error("fcntl F_SETFD error! fd=%d ret=%#x", fd, ret);
            srs_close_stfd(client_stfd);
            return ret;
        }
    }
这段代码的作用见 https://github.com/ossrs/srs/issues/518。说是为了避免fd泄露。我没有看明白。
接下来要创建具体的连接实例
if (type == SrsListenerRtmpStream) {
        conn = new SrsRtmpConn(this, client_stfd);
    }
并把这个实例放入本地的数据结构中
 conns.push_back(conn);
最后调用start()函数。就结束了
if ((ret = conn->start()) != ERROR_SUCCESS) {
        return ret;
    }
比较简单是不。st编程我还没有琢磨透,不过这个的确超出了我的预期。接着我们来分析连接框架。了解下主函数调用了start()之前和之后都发生了什么事情。先来看下连接的继承关系 


由于st线程的便利性。所以srs对待连接和对待侦听的思路是一样的,就是直接开一个线程自生自灭。我们看到连接的基类SrsConnection里,有一个线程变量

SrsOneCycleThread* pthread;

很有意思的一个线程类,这个应该叫做循环一次就死的线程类,查看其循环函数

int SrsOneCycleThread::cycle()
{
    int ret = handler->cycle();
    pthread->stop_loop();
    return ret;
}
果然是在处理类cycle()一次后,就关闭线程。担任如果handler一直不退出cycle(),这个也可以演变成endlesss的类。

为啥连接类要用这个线程基类呢?我想可能是希望处理完连接请求就自动关闭掉吧。特别是大量的http请求。关闭的时候,第二个变量 IConnectionManager* manager就其作用了。看看 IConnectionManager的接口

virtual void remove(SrsConnection* c) = 0;

其实现在server类里

void SrsServer::remove(SrsConnection* conn)
{
    std::vector<SrsConnection*>::iterator it = std::find(conns.begin(), conns.end(), conn);
    
    // removed by destroy, ignore.
    if (it == conns.end()) {
        srs_warn("server moved connection, ignore.");
        return;
    }
    
    conns.erase(it);
    
    srs_info("conn removed. conns=%d", (int)conns.size());
    
    SrsStatistic* stat = SrsStatistic::instance();
    stat->kbps_add_delta(conn);
    stat->on_disconnect(conn->srs_id());
    
    // all connections are created by server,
    // so we free it here.
    srs_freep(conn);
}
这样变实现了连接的自动释放。设计还是比较巧妙滴。


下面来分析下rtmp的连接实例。由于在基类里,

virtual int do_cycle() = 0;
int SrsConnection::cycle()
{
    int ret = ERROR_SUCCESS;
    
    _srs_context->generate_id();
    id = _srs_context->get_id();
    
    ip = srs_get_peer_ip(st_netfd_fileno(stfd));
    
    ret = do_cycle();
    
    // if socket io error, set to closed.
    if (srs_is_client_gracefully_close(ret)) {
        ret = ERROR_SOCKET_CLOSED;
    }
    
    // success.
    if (ret == ERROR_SUCCESS) {
        srs_trace("client finished.");
    }
    
    // client close peer.
    if (ret == ERROR_SOCKET_CLOSED) {
        srs_warn("client disconnect peer. ret=%d", ret);
    }

    return ERROR_SUCCESS;
}


 所有的派生连接类,基本就围绕这个纯虚函数来搞动作。 

下面要开始大戏分析了。rtmp协议的实现。在这里需要分析如下几个点

1)如何实现rtmp servr连接

2)怎么实现hook

3) 怎么实现edge

4)怎么实现forward

6)怎么实现统计


在这之前,我需要在仔细回顾下rmtp协议文档。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值