如何实现带宽速度测试的功能?看看srs开源服务器的实现

本文介绍了如何通过srs服务器进行带宽速度测试。关键在于计算收发数据的字节数和时间,以及自定义数据增长算法。srs服务器的测试带宽函数涉及发送伪装rtmp packet并根据数据大小和时间计算kbps,同时设置了速度上限,超过1000kbps则休息100ms。详细实现可查阅srs_lib_bandwidth.hpp和srs_lib_bandwidth.cpp文件。

一、总结如下几点:

  1. 通过send函数和recv函数计算发送和接收的总字节数,并通过发送和接收的时间段来计算收发比特率。简单的计算为totalsizes/totaltimeduration。
  2. 如何封装发送的数据也是有讲究的,可以自定义一个增量算法,让每次发送的测试数据自动增长。
  3. 每个包发送的时间间隔是否需要设置?这个要看客户端实现,如果是select模型,可以不设置,直到socket出错后重置后继续发送(比如前面介绍的飞秋源码发送文件的实现),有些客户端实现每次send函数中间会sleep一个很小的时间,让sendbuf充分的处理数据后再继续写另一个包的数据,比如sleep个5ms之类的,但测试速度我觉得不合适这么用。
  4. 发送测试数据的总时间,可以自己定义。

二、srs服务器代码分析

(1)测试带宽函数,收发数据的关键代码如下

int SrsBandwidth::do_bandwidth_check(SrsKbpsLimit* limit)
{
    int ret = ERROR_SUCCESS;

    SrsBandwidthSample play_sample;
    SrsBandwidthSample publish_sample;
    
    // timeout for a packet.
    _rtmp->set_send_timeout(play_sample.duration_ms * 1000 * 2);
    _rtmp->set_recv_timeout(publish_sample.duration_ms * 1000 * 2);

    // start test.
    srs_update_system_time_ms();
    int64_t start_time = srs_get_system_time_ms();
    
    // sample play
    srs_info("start play test.");
    
    if ((ret = play_start(&play_sample, limit)) != ERROR_SUCCESS) {
        srs_error("bandwidth play check failed. ret=%d", ret);
        return ret;
    }
    if ((ret = play_checking(&play_sample, limit)) != ERROR_SUCCESS) {
        srs_error("bandwidth play check failed. ret=%d", ret);
        return ret;
    }
    if ((ret = play_stop(&play_sample, limit)) != ERROR_SUCCESS) {
        srs_error("bandwidth play check failed. ret=%d", ret);
        return ret;
    }
    
    srs_info("stop play test. kbps=%d", play_sample.kbps);
    
    // sample publish
    srs_info("start publish test.");
    
    if ((ret = publish_start(&publish_sample, limit)) != ERROR_SUCCESS) {
        srs_error("bandwidth publish check failed. ret=%d", ret);
        return ret;
    }
    if ((ret = publish_checking(&publish_sample, limit)) != ERROR_SUCCESS) {
        srs_error("bandwidth publish check failed. ret=%d", ret);
        return ret;
    }
    if ((ret = publish_stop(&publish_sample, limit)) != ERROR_SUCCESS) {
        srs_error("bandwidth publish check failed. ret=%d", ret);
        return ret;
    }
    
    srs_info("stop publish test. kbps=%d", publish_sample.kbps);

    // stop test.
    srs_update_system_time_ms();
    int64_t end_time = srs_get_system_time_ms();

    srs_trace("bandwidth ok. duartion=%dms(%d+%d), play=%dkbps, publish=%dkbps", 
        (int)(end_time - start_time), play_sample.actual_duration_ms, 
        publish_sample.actual_duration_ms, play_sample.kbps, 
        publish_sample.kbps);
    
    if ((ret = finial(play_sample, publish_sample, start_time, end_time)) != ERROR_SUCCESS) {
        return ret;
    }
    
    st_usleep(_SRS_BANDWIDTH_FINAL_WAIT_MS * 1000);
    srs_info("BW check finished.");

    return ret;
}

解析:

    首先服务器发送伪装rtmp packet给客户端,然后根据发送的数据大小和实际持续时间来计算kbps。

    然后服务器接收客户端发送回来的伪装rtmp packet数据,计算接收的kbps。

(2)发送数据

int SrsBandwidth::play_checking(SrsBandwidthSample* sample, SrsKbpsLimit* limit)
{
    int ret = ERROR_SUCCESS;

    // send play data to client
    int size = 1024; // TODO: FIXME: magic number
    char random_data[size];
    memset(random_data, 'A', size);

    int data_count = 1;
    srs_update_system_time_ms();
    int64_t starttime = srs_get_system_time_ms();
    while ((srs_get_system_time_ms() - starttime) < sample->duration_ms) {
        st_usleep(sample->interval_ms);
        
        // TODO: FIXME: use shared ptr message.
        SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_playing();

        // TODO: FIXME: magic number
        for (int i = 0; i < data_count; ++i) {
            std::stringstream seq;
            seq << i;
            std::string play_data = "SRS band check data from server's playing......";
            pkt->data->set(seq.str(), SrsAmf0Any::str(play_data.c_str()));
        }
        data_count += 2;

        if ((ret = _rtmp->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) {
            srs_error("send bandwidth check play messages failed. ret=%d", ret);
            return ret;
        }
        
        limit->send_limit();
    }
    srs_update_system_time_ms();
    sample->calc_kbps(_rtmp->get_send_bytes(), srs_get_system_time_ms() - starttime);
    srs_info("BW check send play bytes over.");
    
    return ret;
}

其中:

     会先设置一个计划发送持续时间sample->duration_ms(3秒),即while((srs_get_system_time_ms()-starttime) < sample->duration_ms)中的duration_ms。

    封装的数据是根据发送包的序列不断增长的。

// TODO: FIXME: magic number
for (int i = 0; i < data_count; ++i) {
    std::stringstream seq; 
    seq << i;
    std::string play_data = "SRS band check data from server's playing......";
    pkt->data->set(seq.str(), SrsAmf0Any::str(play_data.c_str()));
}
data_count += 2;

(3)包间间隔发送时间,即st_usleep(sample->interval_ms)的休眠时间设置0,如下代码可见interval_ms被初始化为0,后面没有对interval_ms进行改变。

SrsBandwidthSample::SrsBandwidthSample()
{
    duration_ms = _SRS_BANDWIDTH_SAMPLE_DURATION_MS;
    kbps = interval_ms = actual_duration_ms = bytes = 0;
}

(4)设置了一个速度上限,如果大于 1000kbps的速度,则休息一下(100ms)。代码如下:

#define _SRS_BANDWIDTH_LIMIT_INTERVAL_MS 100
void SrsKbpsLimit::send_limit()
{
    _kbps->sample();
    while (_kbps->get_send_kbps() > _limit_kbps) {
        _kbps->sample();
        st_usleep(_SRS_BANDWIDTH_LIMIT_INTERVAL_MS * 1000);
    }
}

三、详细请看srs_lib_bandwidth.hpp和srs_lib_bandwidth.cpp这两个文件。

四、最后看看官网的测试速度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值