首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

OpenRTMFP/Cumulus Primer(四)CumulusServer启动流程分析

2012-07-28 
OpenRTMFP/Cumulus Primer(4)CumulusServer启动流程分析OpenRTMFP/Cumulus Primer(4)CumulusServer启动流

OpenRTMFP/Cumulus Primer(4)CumulusServer启动流程分析

OpenRTMFP/Cumulus Primer(4)CumulusServer启动流程分析
  • 作者:柳大·Poechant(钟超)
  • 博客:Blog.CSDN.net/Poechant
  • 邮箱:zhongchao.ustc#gmail.com (# -> @)
  • 日期:April 14th, 2012

    首先要知道的是,OpenRTMFP/Cumulus中使用到的库有 Poco、OpenSSL 和 Lua。

    1 main.cpp 中的 main() 函数

    入口在 main.cpp 中:

    int main(int argc, char* argv[]) {

    先检查内存泄露,不过目前这个开发中的项目还没有实现这个功能,只是个空函数:

        DetectMemoryLeak();

    然后会创建一个匿名的 CumulusServer 对象,并调用其 run() 函数,该函数由 CumulusServer 从 ServerApplication 中继承而来,而 ServerApplication 由是从 Application 继承而来的。CumulusServer 对象调用 run() 函数,实际是 ServerApplication 的 run() 函数,ServerApplication 的 run() 函数则是调用 Application 的函数,而该 run() 函数则是先调用 initialize() 函数,然后调用 main() 函数,然后调用 uninitialize() 函数。如果 initialize() 函数被调用时抛出异常,则不会执行 main() 函数,但仍然会执行 uninitialize() 函数:

        // Runs the application by performing additional initializations    // and calling the main() method.    return CumulusServer().run(argc, argv);}

    2 main.cpp 中的 CumulusServer() 构造函数

    CumulusServer 的构造函数定义为:

    CumulusServer(): _helpRequested(false), // 显示帮助信息                 _pCirrus(NULL),                 _middle(false),                 _isInteractive(true),                 _pLogFile(NULL) {}

    3 main.cpp 中的 CumulusServer 的 initialize() 成员函数

    在执行 main() 函数之前,CumulusServer 会启动 initialize() 函数,传入的参数就是 CumulusServer 自己,可以猜到 Poco::Util::Application 的 run 方法中,调用该函数时的参数是this

    void initialize(Application& self) {

    调用父函数 ServerApplication 的初始化函数:

        ServerApplication::initialize(self);

    再继续下面的源码分析之前,先要知道,根据Poco::Util::Application,Application 类有一些内置的配置属性,如下:

    • application.path: 可执行文件的绝对路径;
    • application.name: 可执行文件的文件名(含扩展名);
    • application.baseName: 可执行文件的文件名(不含扩展名)
    • application.dir: 可执行文件的所在目录;
    • application.configDir: 配置文件所在目录;

      所以下面就读取了可执行文件的所在目录,其中第二个参数表示默认值(即当前目录):

          string dir = config().getString("application.dir", "./");

      然后读取配置文件,目录为上一句所得到的dir,文件名(不含扩展名)为application.basename内置配置属性值,其默认值为CumulusServer,然后加上点和扩展名.ini

          loadConfiguration(dir        + config().getString("application.baseName", "CumulusServer")        + ".ini");

      这样就加载完配置了。然后查看当前的进程是从命令行运行的(命令行是交互的,所以是 interactive),还是以 daemon 方式运行的,这个函数是ServerApplication的一个成员函数:

          _isInteractive = isInteractive();

      然后获取表示日志文件所在目录的字符串,其中logs.directory是外置配置属性(配置文件中),其默认值为上面获取到的可执行文件路径(一般为当前路径)与logs的组合,即一般为当前目录下的logs目录:

          string logDir(config().getString("logs.directory", dir + "logs"));

      创建日志文件目录:

          File(logDir).createDirectory();

      日志文件绝对路径,logs为默认的日志文件名(不含扩展名的部分),扩展名用0

          _logPath = logDir + "/" + config().getString("logs.name", "log") + ".";    _pLogFile = new File(_logPath + "0");

      用日志流打开日志文件(方式为追加写入):

          _logStream.open(_pLogFile->path(), ios::in | ios::ate);

      Logs 是一个方法类(其中的 public 函数都是静态的),SetLogger的作用就是将Logs中的似有静态成员设置为某个 Cumulus::Logger 对象(由于 CumulusServer 继承了 Cumulus::Logger)。

          Logs::SetLogger(*this);}

      4 main.cpp 中的 CumulusServer 的 main() 成员函数

      OpenRTMFP/Cumulus是一个基于Poco::Util::Application的服务端应用(准确的说是基于Poco::Util::ServerApplication的服务端应用)。如果没有特殊的启动要求,可以调用Poco/Application.h中定义的宏POCO_APP_MAIN来完成初始化、日志和启动(该宏会根据不同的平台启用不同的main()函数)。

      run() 函数在调用完 initialize() 函数后,会调用 CumulusServer 中的 main() 函数,该 main() 函数的定义在 main.cpp 中:

      int main(const std::vector<std::string>& args) {

      首先看是否是要求帮助信息,displayHelp是借助Poco::Util::HelpFormatter实现的,CumulusServer的构造函数会在调用时将_helpRequested设置为false

          if (_helpRequested) {        displayHelp();    }

      如果不是,则进入启动状态,首先创建一个RTMFPServerParams对象params,用来存储OpenRTMFP/CumulusServer的基本配置信息。

          else {        try {            RTMFPServerParams params;

      params存储CumulusServer的端口号和CumulusEdge的端口号:

                  params.port = config().getInt("port", params.port);            UInt16 edgesPort = config().getInt("edges.port",                RTMFP_DEFAULT_PORT+1);            if(config().getBool("edges.activated",false)) {                if(edgesPort==0)                    WARN("edges.port must have a positive value if \                          edges.activated is true. Server edges is \                          disactivated.");                params.edgesPort=edgesPort;            }

      _pCirrusSocketAddress的成员,是封装IP地址和端口号的对象。

                  params.pCirrus = _pCirrus;            params.middle = _middle;

      UDB 所使用的缓冲区大小:

                  params.udpBufferSize = config().getInt("udpBufferSize",                params.udpBufferSize);            params.keepAliveServer = config().getInt(                "keepAliveServer",params.keepAliveServer);            params.keepAlivePeer = config().getInt("keepAlivePeer",                params.keepAlivePeer);

      失败前CumulusEdge的尝试次数:

                  params.edgesAttemptsBeforeFallback = config().getInt(                "edges.attemptsBeforeFallback",                params.edgesAttemptsBeforeFallback);            Server server(config().getString("application.dir","./"),                *this,config());            server.start(params);

      waitForTerminationRequest()函数是main()函数中必须调用的,意为等待终止运行的操作请求。

                  // wait for CTRL-C or kill            waitForTerminationRequest();

      一旦接收到终止操作的请求,就会执行下面这句,用以退出OpenRTMFP/Cumulus的运行:

                  // Stop the server            server.stop();

      catch 一些可能产生的异常:

              } catch(Exception& ex) {            FATAL("Configuration problem : %s",ex.displayText().c_str());        } catch (exception& ex) {            FATAL("CumulusServer : %s",ex.what());        } catch (...) {            FATAL("CumulusServer unknown error");        }    }

      OpenRTMFP/CumulusServer 停止运行:

          return Application::EXIT_OK;}

      -

      转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant

      -

热点排行