SRS学习笔记2

main函数分析:

位于main\srs_main_server.cpp

// never use srs log(srs_trace, srs_error, etc) before config parse the option,
    // which will load the log config and apply it.
    if ((ret = _srs_config->parse_options(argc, argv)) != ERROR_SUCCESS) {
        return ret;
    }

先调用 SrsConfig类的 parse_options函数解析命令行参数

位于app\srs_app_config.cpp

// see: ngx_get_options
int SrsConfig::parse_options(int argc, char** argv)
{
    int ret = ERROR_SUCCESS;

    // argv
    for (int i = 0; i < argc; i++) {
        _argv.append(argv[i]);

        if (i < argc - 1) {
            _argv.append(" ");
        }
    }

    // config
    show_help = true;
    for (int i = 1; i < argc; i++) {
        if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {
            return ret;
        }
    }

    if (show_help) {
        print_help(argv);
        exit(0);
    }

    if (show_version) {
        fprintf(stderr, "%s\n", RTMP_SIG_SRS_VERSION);
        exit(0);
    }

    // first hello message.
    srs_trace(_srs_version);

    if (config_file.empty()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);
        return ret;
    }

    ret = parse_file(config_file.c_str());

    if (test_conf) {
        // the parse_file never check the config,
        // we check it when user requires check config file.
        if (ret == ERROR_SUCCESS) {
            ret = check_config();
        }

        if (ret == ERROR_SUCCESS) {
            srs_trace("config file is ok");
            exit(0);
        } else {
            srs_error("config file is invalid");
            exit(ret);
        }
    }

    ////////////////////////////////////////////////////////////////////////
    // check log name and level
    ////////////////////////////////////////////////////////////////////////
    if (true) {
        std::string log_filename = this->get_log_file();
        if (get_log_tank_file() && log_filename.empty()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("must specifies the file to write log to. ret=%d", ret);
            return ret;
        }
        if (get_log_tank_file()) {
            srs_trace("write log to file %s", log_filename.c_str());
            srs_trace("you can: tailf %s", log_filename.c_str());
            srs_trace("@see: %s", SRS_WIKI_URL_LOG);
        } else {
            srs_trace("write log to console");
        }
    }

    return ret;
}

parse_options 函数的作用如下

1. 将命令行参数保存在成员变量_argv(std::string),参数之间用空格分隔.

2. 调用 parse_argv函数对命令行参数进行分析,并设置相应的标志变量,

  show_help(显示帮助信息后退出)

  test_conf(测试配置文件后退出)

  show_version(显示版本信息后退出)

  config_file(保存从命令行传入的配置文件路径)

3. show_help和show_version都等于false,调用 parse_file函数

 ret = parse_file(config_file.c_str());

    if (test_conf) {
        // the parse_file never check the config,
        // we check it when user requires check config file.
        if (ret == ERROR_SUCCESS) {
            ret = check_config();
        }

        if (ret == ERROR_SUCCESS) {
            srs_trace("config file is ok");
            exit(0);
        } else {
            srs_error("config file is invalid");
            exit(ret);
        }
    }

如果测试配置,调用check_config函数检查配置信息

4.检查写日志到控制台还是文件,如果是文件,检查文件名是否不为空

////////////////////////////////////////////////////////////////////////
    // check log name and level
    ////////////////////////////////////////////////////////////////////////
    if (true) {
        std::string log_filename = this->get_log_file();
        if (get_log_tank_file() && log_filename.empty()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("must specifies the file to write log to. ret=%d", ret);
            return ret;
        }
        if (get_log_tank_file()) {
            srs_trace("write log to file %s", log_filename.c_str());
            srs_trace("you can: tailf %s", log_filename.c_str());
            srs_trace("@see: %s", SRS_WIKI_URL_LOG);
        } else {
            srs_trace("write log to console");
        }
    }

parse_file函数

int SrsConfig::parse_file(const char* filename)
{
    int ret = ERROR_SUCCESS;

    config_file = filename;

    if (config_file.empty()) {
        return ERROR_SYSTEM_CONFIG_INVALID;
    }

    SrsConfigBuffer buffer;

    if ((ret = buffer.fullfill(config_file.c_str())) != ERROR_SUCCESS) {
        return ret;
    }

    return parse_buffer(&buffer);
}

1. 调用 SrsConfigBuffer函数 fullfill填充缓冲区

2. 调用 parse_buffer解析配置

int SrsConfigBuffer::fullfill(const char* filename)
    {
        int ret = ERROR_SUCCESS;

        SrsFileReader reader;

        // open file reader.
        if ((ret = reader.open(filename)) != ERROR_SUCCESS) {
            srs_error("open conf file error. ret=%d", ret);
            return ret;
        }

        // read all.
        int filesize = (int)reader.filesize();

        // create buffer
        srs_freepa(start);
        pos = last = start = new char[filesize];
        end = start + filesize;

        // read total content from file.
        ssize_t nread = 0;
        if ((ret = reader.read(start, filesize, &nread)) != ERROR_SUCCESS) {
            srs_error("read file read error. expect %d, actual %d bytes, ret=%d",
                filesize, nread, ret);
            return ret;
        }

        return ret;
    }

调用SrsFileReader类读配置文件内容到SrsConfigBuffer类的内部缓冲区,设置start,end,pos.last指针

SrsFileReader类位于kernel\srs_kernel_file.cpp

int SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
{
    int ret = ERROR_SUCCESS;

    if ((ret = root->parse(buffer)) != ERROR_SUCCESS) {
        return ret;
    }

    // mock by dolphin mode.
    // for the dolphin will start srs with specified params.
    if (dolphin) {
        // for RTMP.
        set_config_directive(root, "listen", dolphin_rtmp_port);

        // for HTTP
        set_config_directive(root, "http_server", "");
        SrsConfDirective* http_server = root->get("http_server");
        set_config_directive(http_server, "enabled", "on");
        set_config_directive(http_server, "listen", dolphin_http_port);

        // others.
        set_config_directive(root, "daemon", "off");
        set_config_directive(root, "srs_log_tank", "console");
    }

    return ret;
}

root变量的类型SrsConfDirective

int SrsConfDirective::parse(SrsConfigBuffer* buffer)
{
    return parse_conf(buffer, parse_file);
}
parse_file枚举变量
/**
    * the directive parsing type.
    */
    enum SrsDirectiveType {
        /**
        * the root directives, parsing file.
        */
        parse_file,
        /**
        * for each direcitve, parsing text block.
        */
        parse_block
    // see: ngx_conf_parseint SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type){int ret = ERROR_SUCCESS;
while (true) {
        std::vector<string> args;
        int line_start = 0;
        ret = read_token(buffer, args, line_start);
        // 从buffer中读一行数据,args返回单词数组,line_start返回当前行数       /**
        * ret maybe:
        * ERROR_SYSTEM_CONFIG_INVALID           error.
        * ERROR_SYSTEM_CONFIG_DIRECTIVE         directive terminated by ‘;‘ found
        * ERROR_SYSTEM_CONFIG_BLOCK_START       token terminated by ‘{‘ found
        * ERROR_SYSTEM_CONFIG_BLOCK_END         the ‘}‘ found
        * ERROR_SYSTEM_CONFIG_EOF               the config file is done
        */
        if (ret == ERROR_SYSTEM_CONFIG_INVALID) {
            return ret;
        }
        if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {
        if (type != parse_block) {        // 此时没有遇到 { type 是 parse_file// 相当于 } 没有匹配的 {               srs_error("line %d: unexpected \"}\", ret=%d", buffer->line, ret);
                return ret;
            }
            return ERROR_SUCCESS;
        }
        if (ret == ERROR_SYSTEM_CONFIG_EOF) {
            if (type == parse_block) {// { 没有匹配的 }              srs_error("line %d: unexpected end of file, expecting \"}\", ret=%d", conf_line, ret);
                return ret;
            }
            return ERROR_SUCCESS;
        }

        if (args.empty()) {//            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("line %d: empty directive. ret=%d", conf_line, ret);
            return ret;
        }

        // build directive tree.
        SrsConfDirective* directive = new SrsConfDirective();

        directive->conf_line = line_start;
        directive->name = args[0];
        args.erase(args.begin());
        directive->args.swap(args);

        directives.push_back(directive);
        // 解析 {} 里面的内容
        if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {
            if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {
                return ret;
            }
        }
    }

    return ret;
}
// see: ngx_conf_read_token
int SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector<string>& args, int& line_start)
{
    int ret = ERROR_SUCCESS;

    char* pstart = buffer->pos;

    bool sharp_comment = false;

    bool d_quoted = false;
    bool s_quoted = false;

    bool need_space = false;
    bool last_space = true;

    while (true) {
        if (buffer->empty()) {
            ret = ERROR_SYSTEM_CONFIG_EOF;

            if (!args.empty() || !last_space) {
                srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);
                return ERROR_SYSTEM_CONFIG_INVALID;
            }
            srs_trace("config parse complete");

            return ret;
        }

        char ch = *buffer->pos++;

        if (ch == SRS_LF) {
            buffer->line++;
            sharp_comment = false;
        }

        if (sharp_comment) {
            continue;
        }

        if (need_space) {
            if (is_common_space(ch)) {
                last_space = true;
                need_space = false;
                continue;
            }
            if (ch == ‘;‘) {
                return ERROR_SYSTEM_CONFIG_DIRECTIVE;
            }
            if (ch == ‘{‘) {
                return ERROR_SYSTEM_CONFIG_BLOCK_START;
            }
            srs_error("line %d: unexpected ‘%c‘", buffer->line, ch);
            return ERROR_SYSTEM_CONFIG_INVALID;
        }

        // last charecter is space.
        if (last_space) {
            if (is_common_space(ch)) {
                continue;
            }
            pstart = buffer->pos - 1;
            switch (ch) {
                case ‘;‘:
                    if (args.size() == 0) {//只有一个 ;的一行                       srs_error("line %d: unexpected ‘;‘", buffer->line);
                        return ERROR_SYSTEM_CONFIG_INVALID;
                    }
                    return ERROR_SYSTEM_CONFIG_DIRECTIVE;
                case ‘{‘://只有一个 { 的一行

if (args.size() == 0) {
                        srs_error("line %d: unexpected ‘{‘", buffer->line);
                        return ERROR_SYSTEM_CONFIG_INVALID;
                    }
                    return ERROR_SYSTEM_CONFIG_BLOCK_START;
                case ‘}‘:
                    if (args.size() != 0) {
                        srs_error("line %d: unexpected ‘}‘", buffer->line);
                        return ERROR_SYSTEM_CONFIG_INVALID;
                    }
                    return ERROR_SYSTEM_CONFIG_BLOCK_END;
                case ‘#‘:
                    sharp_comment = 1;
                    continue;
                case ‘"‘:
                    pstart++;
                    d_quoted = true;
                    last_space = 0;
                    continue;
                case ‘\‘‘:
                    pstart++;
                    s_quoted = true;
                    last_space = 0;
                    continue;
                default:
                    last_space = 0;
                    continue;
            }
        } else {
        // last charecter is not space
            if (line_start == 0) {
                line_start = buffer->line;
            }

            bool found = false;
            if (d_quoted) {
                if (ch == ‘"‘) {
                    d_quoted = false;
                    need_space = true;
                    found = true;
                }
            } else if (s_quoted) {
                if (ch == ‘\‘‘) {
                    s_quoted = false;
                    need_space = true;
                    found = true;
                }
            } else if (is_common_space(ch) || ch == ‘;‘ || ch == ‘{‘) {
                last_space = true;
                found = 1;
            }

            if (found) {
                int len = (int)(buffer->pos - pstart);
                char* aword = new char[len];
                memcpy(aword, pstart, len);
                aword[len - 1] = 0;

                string word_str = aword;
                if (!word_str.empty()) {
                    args.push_back(word_str);
                }
                srs_freepa(aword);

                if (ch == ‘;‘) {
                    return ERROR_SYSTEM_CONFIG_DIRECTIVE;
                }
                if (ch == ‘{‘) {
                    return ERROR_SYSTEM_CONFIG_BLOCK_START;
                }
            }
        }
    }

    return ret;
}

至此 parse_file函数分析完毕,下一篇分析check_config函数

未完待续...

 
时间: 2024-11-07 15:04:12

SRS学习笔记2的相关文章

SRS学习笔记12-SRSSOUCE类分析3

int SrsPublishEdge::initialize(SrsSource* source, SrsRequest* req) { int ret = ERROR_SUCCESS; if ((ret = forwarder->initialize(source, this, req)) != ERROR_SUCCESS) { return ret; } return ret; } bool SrsPublishEdge::can_publish() { return state != Sr

SRS学习笔记10-SrsConnection及其子类分析

SrsConnection类代表一个client的连接,其中封装了st thread,用于在一个单独的st thread里处理一个client的服务请求. SrsConnection在 int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)里创建 SrsConnection* conn = NULL; if (type == SrsListenerRtmpStream) { conn = new Srs

测试方法(个人学习笔记20170305)

测试方法(个人学习笔记20170305) 测试方法: 按对象分类:黑盒,灰盒,白盒 按是否执行程序分类:静态,动态 按手段分类:手工,自动化 黑盒 1.依据:需求规格说明书(SRS) 2.测试对象:整个软件产品 3.目的 理论目的:检查软件功能实现是否符合SRS 实际目的:尽早验收或售卖 4.评估标准:需求覆盖率100%(最低标准) 需求覆盖率=被测需求数/总需求数 5.介入时间:系统测试阶段(ST)(已开发完成,可操作执行) 6.优点:简单 7.缺点:介入时间晚,修复成本高,无法测试内部逻辑和

SAS学习笔记

一.            在SAS中进行随机抽样: 1. 在实际数据处理中常常需要进行样本抽样,在实践中主要有两种情况: (1)简单无重复抽样(2)分层抽样   a.等比例分层抽样  b. 不等比例分层抽样: 2.SAS 中可以利用PROC suveryselect 过程实现各种抽样: 其一般形式是: PROC SURVEYSELECT  data=<源数据集名> method = <srslursl sys >  out=<抽取样本存放的数据集> n=<抽取数

端口相关知识学习笔记

端口相关知识学习笔记 端口相关知识学习笔记 本周主要精力是放在挂接上,所以知识矩阵的学习回归到根本上,所以这周发的学习笔记是关于计算机端口的相关介绍. 有过一些黑客攻击方面知识的读者都会知道,其实那些所谓的黑客并不是像人们想象那样从天而降,而是实实在在从您的计算机"大门"中自由出入.计算机的" 大门"就是我们平常所说的"端口",它包括计算机的物理端口,如计算机的串口.并口.输入/输出设备以及适配器接口等(这些端口都是可见的),但更多的是不可见的软

vector 学习笔记

vector 使用练习: /**************************************** * File Name: vector.cpp * Author: sky0917 * Created Time: 2014年04月27日 11:07:33 ****************************************/ #include <iostream> #include <vector> using namespace std; int main

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细,自己在看它的文档和代码时写了一些demo和笔记,还有它实现的原理记录一下 学习Caliburn.Micro要有MEF和MVVM的基础 先说一下他的命名规则和引导类 以后我会把Caliburn.Micro的 Actions IResult,IHandle ICondu

jQuery学习笔记(一):入门

jQuery学习笔记(一):入门 一.JQuery是什么 JQuery是什么?始终是萦绕在我心中的一个问题: 借鉴网上同学们的总结,可以从以下几个方面观察. 不使用JQuery时获取DOM文本的操作如下: 1 document.getElementById('info').value = 'Hello World!'; 使用JQuery时获取DOM文本操作如下: 1 $('#info').val('Hello World!'); 嗯,可以看出,使用JQuery的优势之一是可以使代码更加简练,使开

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------