在 Post Read Configuration 中使用 ap_retained_data_create/get 开发
Developing Cross Platform Apache Modules using ap_retained_data_create/get in Post Read Config
在构建跨平台模块时,我非常高兴地在 Apache 2.4 的设计中调试了几个小时。
我面临的问题是 Apache 在启动时加载配置文件两次,从而加载模块本身两次。一旦我猜到测试配置并读取命令结构,然后下一步填写服务器运行的空白。这通常不会有任何问题,但我需要在为任何客户端提供服务之前在加载时加载模块的配置,并且只解析我的模块需求一次且仅一次。
由于我使用了许多资源,包括数据库等,因此我认为多次运行不是最好的主意,尤其是在数据库服务器上受到攻击时。
在线手册("开发人员 API 2.5")说,不要使用旧方法,我将让读者查找,而是使用ap_retained_data_get和ap_retained_data_create在模块卸载时保留数据。最好将标志传递到已通过测试阶段的下一阶段。
这就是头痛所在。这不是它在Windows上的工作方式。
Linux 确实以两次方式运行,但 Windows 以四次运行。
在配置后读取钩子中使用此方法适用于 Linux,但不适用于 Windows
// variables for base config start
const char *flag = "some_prefixed_flag_to_mashup_with_other_flags";
void *init_flag = NULL;
int dbl = APLOG_TRACE4;
// logger
logging logger(NULL, s, p);
// determine if this is the first time we have loaded
init_flag = ap_retained_data_get(flag);
// check flag result
if (init_flag == NULL)
{
// breakpoint
stdLog(logger, INFX_LOG_DATA, dbl);
// set first time flag local
ap_retained_data_create(flag, 1);
}
// call initization routine
else
{
// do something here
}
请注意,我在模块中导出C++代码,因此使用类。此外,为简洁起见,缺少一些变量声明。
所以这对Windows来说应该足够了吧?错。我必须反向学习,因为我首先在Windows上构建,但是Windows有四次而不是两次。那里的初始化仍将运行两次。
我的下一个解决方案如下:
// variables for base config start
const char *flag = "some_prefixed_flag_to_mashup_with_other_flags";
void *init_flag = NULL;
char *pidname;
int dbl = APLOG_TRACE4;
pid_t pidNKey;
apr_file_t *pidfile;
// logger
logging logger(NULL, s, p);
// determine if this is the first time we have loaded
init_flag = ap_retained_data_get(flag);
// check flag result
if (init_flag == NULL)
{
// breakpoint
stdLog(logger, INFX_LOG_DATA, dbl);
// set first time flag local
ap_retained_data_create(flag, 1);
}
else
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// create a pid if not exists
if (ap_read_pid(p, "logs/httpd.pid", &pidNKey) == OK)
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// create a pid especially for our setup
pidname = apr_psprintf(ptemp, "logs/infx.%d.pid", pidNKey);
// if pidfile does not exist then create it
if (!fileExists(pidname, ptemp))
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// create the pid
apr_file_open(&pidfile, pidname, APR_WRITE|APR_APPEND|APR_CREATE, INFX_BASE_PERM, ptemp);
// add nonsensical data to it
apr_file_puts("1", pidfile);
// cllose the file and wait for run 2
apr_file_close(pidfile);
}
// begin work
else
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// we no longer require the pid file
apr_file_remove(pidname, ptemp);
}
}
}
似乎有效....好的,我完成了这一部分,对吧?错!我去了Linux盒子和隔离区间城市。我敢肯定,许多经验丰富的Apache开发人员现在可能会摇头,但这些人并没有记录这些问题。
我的最终解决方法是将 Windows 代码包装在定义块中。我不确定是否有更好的方法,但它对我有用。因此,以下内容在两个平台上都有效,没有段错误。
// variables for base config start
const char *flag = "some_prefixed_flag_to_mashup_with_other_flags";
void *init_flag = NULL;
int dbl = APLOG_TRACE4;
// logger
logging logger(NULL, s, p);
// determine if this is the first time we have loaded
init_flag = ap_retained_data_get(flag);
// check flag result
if (init_flag == NULL)
{
// breakpoint
stdLog(logger, INFX_LOG_DATA, dbl);
// set first time flag local
ap_retained_data_create(flag, 1);
}
// call initization routine
else
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
#if defined(WIN32)
// create a pid if not exists
if (ap_read_pid(p, "logs/httpd.pid", &pidNKey) == OK)
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// create a pid especially for our setup
pidname = apr_psprintf(ptemp, "logs/infx.%d.pid", pidNKey);
// if pidfile does not exist then create it
if (!fileExists(pidname, ptemp))
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// create the pid
apr_file_open(&pidfile, pidname, APR_WRITE|APR_APPEND|APR_CREATE, INFX_BASE_PERM, ptemp);
// add nonsensical data to it
apr_file_puts("1", pidfile);
// cllose the file and wait for run 2
apr_file_close(pidfile);
}
// begin work
else
{
// break point
stdLog(logger, INFX_LOG_DATA, dbl);
// we no longer require the pid file
apr_file_remove(pidname, ptemp);
#endif
// do something here for both platforms
#if defined(WIN32)
}
}
// crash if we do get a proper pid
else
{
// breakpoint
stdLog(logger, INFX_LOG_DATA, APLOG_CRIT, "HTTPD File not found? A Bug?");
// set status
return HTTP_INTERNAL_SERVER_ERROR;
}
#endif
}
希望其他人可以从中受益。
- 如何处理 c++ 中类实现中的"invalid use of non-static data member"?
- 'string.assign(string.data(), 5)' 是明确定义的还是 UB?
- 收到错误"invalid use of non-static data member 'stu::n' "
- C++ 初始化 .data 部分中的变量
- 模式"allocate memory or use existing data"
- boost::asio data owning `ConstBufferSequence`
- Python to C++ Data structure API
- 当初始值设定项是基类名时'initializer does not name a non-static data member or base class'错误
- protobuf C++ SQLite handle blob data
- 错误:字段'dateOfBirth'的类型不完整'Poco::Data::Date'
- 为什么构造函数 Message(const T&data) 与 Message(T&& data) 冲突,当 T = int&时?
- "thread-safe data"与"thread-safe code/functions"的区别
- 如何找到目标文件 *.o 的 ram rom 使用情况(.bss .text .rodata .data)?
- 这在C++ "It does not own the underlying data, and so is cheap to copy or assign"中意味着什么
- 使用 .data() 将字符数组转换为 std::string 不会转换整个数组
- *(int*)&data[18]在这段代码中实际上做了什么?
- 出现这种错误的原因是什么"invalid use of non-static data member "
- 构造中错误:未在此范围中声明"data"
- 我可以在初始化之前使用 std::array 成员变量中的 data() 指针吗?发出警告
- 如何将data[i].int转换为vaible