当前位置: 首页 > 工具软件 > Gearmand > 使用案例 >

Gearmand学习2:main函数

龙飞文
2023-12-01

  学习开源的软件,最重要的要找到入口,从入口开始学习是至关重要的,就像一团杂乱无章的线团,只要我们能够找到线头,一切都是那么的简单,而入口main函数就是这团杂乱无章的线头。废话少说,下面我们就从main函数开始学习。
  main函数主要完成以下功能:

  • 完成参数解析
  • 完成插件以及配置的初始化
  • 完成服务启动初始化以及服务启动

参数解析

  这里参数解析采用的是boost库program_options,简介请参考Boost.Program_options简述,专业版请参考Boost.Program_options。参数分成两部分,第一部分是命令行参数,第二部分是配置文件参数(如果命令行中指定了config-file)。

  boost::program_options::options_description all("Allowed options");
  //指定通用的配置参数
  all.add(general);
  //指定HTTP的配置参数
  gearmand::protocol::HTTP http;
  all.add(http.command_line_options());
  //指定gear的配置参数
  gearmand::protocol::Gear gear;
  all.add(gear.command_line_options());
  //指定插件的配置参数
  gearmand::plugins::initialize(all);
  boost::program_options::positional_options_description positional;
  positional.add("provided", -1);
  // 指定help参数可见的选项
  boost::program_options::options_description visible("Allowed options");
  visible.add(all);
  //指定用户不可见的选项
  boost::program_options::options_description hidden("Hidden options");
  hidden.add_options()
  ("check-args", boost::program_options::bool_switch(&opt_check_args)->default_value(false),
   "Check command line and configuration file argments and then exit.");
  all.add(hidden);
  //解析命令行配置参数
  // Disable allow_guessing
  int style= boost::program_options::command_line_style::default_style ^ boost::program_options::command_line_style::allow_guessing;
  boost::program_options::parsed_options parsed= boost::program_options::command_line_parser(argc, argv)
      .options(all)
      .positional(positional)
      .style(style)
      .run();
  store(parsed, vm);
  notify(vm);

  当指定了config-file选项时,则会解析配置文件,这里需要注意的是,当配置文件指定的参数和命令行指定的参数重复时,将会以命令行指定的为准。program_options中最先解析的参数将覆盖最后解析的,在程序中先解析命令行参数,后解析配置文件。

std::ifstream ifs(config_file.c_str());
if (ifs)
{
    //读取文件内容
    std::stringstream ss;
    ss << ifs.rdbuf();
    //按行拆分,并转换为每个配置
    boost::char_separator<char> sep(" \n\r");
    std::string sstr= ss.str();
    boost::tokenizer<boost::char_separator<char> > tok(sstr, sep);
    std::vector<std::string> args;
    std::copy(tok.begin(), tok.end(), back_inserter(args));
    for (std::vector<std::string>::iterator iter= args.begin();iter != args.end();++iter)
    {
      std::cerr << *iter << std::endl;
    }
    //解析配置文件内容
    store(boost::program_options::command_line_parser(args).options(visible).run(), vm);
}
notify(vm);

初始化

//解析日志的级别
gearmand_verbose_t verbose= GEARMAND_VERBOSE_ERROR;
if (gearmand_verbose_check(verbose_string.c_str(), verbose) == false)
{
  error::message("Invalid value for --verbose supplied");
  return EXIT_FAILURE;
}

if (hashtable_buckets <= 0)
{
  error::message("hashtable-buckets has to be greater than 0");
  return EXIT_FAILURE;
}

if (opt_check_args)
{
  return EXIT_SUCCESS;
}

//指定帮助信息时,输出相应的帮助信息
if (vm.count("help"))
{
  std::cout << visible << std::endl;
  return EXIT_SUCCESS;
}
//输出version信息
if (vm.count("version"))
{
  std::cout << std::endl << "gearmand " << gearmand_version() << " - " <<  gearmand_bugreport() << std::endl;
  return EXIT_SUCCESS;
}
//设置能够打开的最大文件描述符个数
if (fds > 0 and _set_fdlimit(fds))
{
  return EXIT_FAILURE;
}
#当为root时,切换到指定的用户名
if (not user.empty() and _switch_user(user.c_str()))
{
  return EXIT_FAILURE;
}
//启动daemon,后面还需要关闭父进程打开的文件描述符才能完全的完成daemon化
if (opt_daemon)
{
  util::daemonize(false, true);
}
//设置相应的信号处理句柄
if (_set_signals(opt_coredump))
{
  return EXIT_FAILURE;
}
//记录进程启动的pid
util::Pidfile _pid_file(pid_file);

if (_pid_file.create() == false and pid_file.compare(GEARMAND_PID))
{
  error::perror(_pid_file.error_message().c_str());
  return EXIT_FAILURE;
}
//初始化日志的配置
gearmand::gearmand_log_info_st log_info(log_file, opt_syslog);

if (log_info.initialized() == false)
{
  return EXIT_FAILURE;
}
//设置开启的线程数
if (threads == 0)
{
  uint32_t number_of_threads= libtest::number_of_cpus();

  if (number_of_threads > 4)
  {
    threads= number_of_threads;
  }
}

服务初始化及启动

//初始化gearman的配置
gearmand_config_st *gearmand_config= gearmand_config_create();
if (gearmand_config == NULL)
{
  return EXIT_FAILURE;
}
//初始化socket选项
gearmand_config_sockopt_keepalive(gearmand_config, opt_keepalive);
//初始化gearman配置
gearmand_st *_gearmand= gearmand_create(gearmand_config,
    host.empty() ? NULL : host.c_str(),threads,backlog,
  job_handle_prefix.empty()?NULL:job_handle_prefix.c_str(),
    static_cast<uint8_t>(worker_wakeup),_log, &log_info, 
    hashtable_buckets);
if (_gearmand == NULL)
{
  error::message("Could not create gearmand library instance.");
  return EXIT_FAILURE;
}

gearmand_config_free(gearmand_config);
//初始化插件
assert(queue_type.size());
if (queue_type.empty() == false)
{
  gearmand_error_t rc;
  if ((rc= gearmand::queue::initialize(_gearmand, queue_type.c_str())) != GEARMAND_SUCCESS)
  {
    error::message("Error while initializing the queue", queue_type.c_str());
    gearmand_free(_gearmand);

    return EXIT_FAILURE;
  }
}
//初始化gearman
if (gear.start(_gearmand) != GEARMAND_SUCCESS)
{
  error::message("Error while enabling Gear protocol module");
  gearmand_free(_gearmand);
  return EXIT_FAILURE;
}
//初始化http
if (protocol.compare("http") == 0)
{
  if (http.start(_gearmand) != GEARMAND_SUCCESS)
  {
    error::message("Error while enabling protocol module", protocol.c_str());
    gearmand_free(_gearmand);
    return EXIT_FAILURE;
  }
}
else if (protocol.empty() == false)
{
  error::message("Unknown protocol module", protocol.c_str());
  gearmand_free(_gearmand);
  return EXIT_FAILURE;
}
//关闭父进程打开的文件描述符,完成最后的daemon
if (opt_daemon)
{
  if (util::daemon_is_ready(true) == false)
  {
    return EXIT_FAILURE;
  }
}
//开启事件处理线程,正式开始提供服务(死循环)
gearmand_error_t ret= gearmand_run(_gearmand);
//释放gearman的资源
gearmand_free(_gearmand);
_gearmand= NULL;

  至此,main函数我们已经学习完毕了,后面我们就跟深入的学习他的插件以及具体的run里面的内容。下面我们先学习插件,了解你其插件的工作模式。

 类似资料: