作者:吴尔平 来源:博客园 酷勤网收集 2007-09-12
ACE 是一个很大的东西,每个人学习路径可能都不一样。我的方法首先阅读 C++ Network Programming, Volume 1 ,让自己明了ACE 的设计思路;再从实际的小项目入手,逐步的用 ACE 内容替换掉自己的东西,在比较和实践之间求得较深的了解。
就一个正常项目而言,一个配置文件是必不可少的,那就先从这里入手了。linux/unix 程序可能经常用到命令行方式,不过我还是比较喜欢 windows 的 ini 格式的,当然,有xml 的更好,不过 ACE 里暂时没有提供。配置文件的使用很简单,ACE 提供的类也很友好。在这里主要是整理一些细节,让大家不在这里浪费太多时间。
1、ACE 配置类简介与使用
先给出一个印象(为了直指主题,所有错误处理都被清除,具体例子请看最后源码):
config.open();
可以浏览一下 ACE_Configuration_Heap 和 ACE_Ini_ImpExp 或 ACE_Registry_ImpExp 之间的关系。不需要套上术语来理解,简化一下代码对此很有帮助。
一个超简化的ACE_Configuration_Heap
2
3
4
5
6
值得注意的是 ACE_Registry_ImpExp 和 ACE_Ini_ImpExp ,这两个类都继承自 ACE_Config_ImpExp_Base,分别处理不同的格式。
简化版本的 ACE_Config_ImpExp_Base, 具体实现请看 Configuration_Import_Export.h
2
3
4
5
6
7
8
9
从两个简化的类,可以想象 ACE_Registry_ImpExp 和 ACE_Ini_ImpExp对import_config的具体实现会将不同格式的文件里的配置数据转化成相同的格式化的数据,并将之放到 ACE_Configuration_Heap 的 SECTION_MAP *index_。 ACE_Config_ImpExp_Base 具体实现的作用就是作为一个适配器。
2、ACE 配置格式说明:
(内容来自Configuration_Import_Export.h的注释)
2.1. ACE_Registry_ImpExp
使用win32 注册表文件导出文件格式,格式如下:
2.2. ACE_Ini_ImpExp
从文件中导入字符串配置数据。充许 not-typed 值(没有 #,dword: hex:, 等前缀),在标准的.ini和.conf中跳过空白字符(tabs和spaces)。 值 (在等式的右边)可以被双引号限定,使得tabs或spaces能够留在字符串中。调用者必须自己转换字符串到类型。格式如下:
3、一个友好的函数
使用此类配置文件时,如果用到会变化的配置集合,我们经常遇到这样的写法
这样写因为 window 提供的 API 只能一项一项读取,我们只能在读取了size 的值后,才能拼凑出"item_1"键名来取到相应的值。在实际操作中维护人员很容易遗漏操作,增加了选项但忘记增加size的值。ACE则提供了非常友好的enumerate_values函数,配合一下 boost 的 split 使用起来感觉很好。
一个非常简单的TCP转发程序的配置文件,将一端口接收到的数据转发至指定地址的端口,可以开多个服务端口:
实际的代码摘录,但不一定能编译呵 :-)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
这样就可以不写
2
3
这样的代码了,也避免了维护人员遗漏操作
4、编译选项
上面代码有用到 boost 的相关内容,如果你使用的是 ACE Programmer's Guide 的 2.5 How to Build Your Applications 节所介绍的Makefile,在 linux 下面的话是不可少的
CPPFLAGS = -i"$(BOOST_ROOT)"
当然,还要在.bash_profile或相应原地方加入类似说明:
BOOST_ROOT=$HOME/boost_X_XX_X
export BOOST_ROOT
//WuErPing 补充 (2006/12/28 )
5、Use Unicode Character Set/Use Multi-Byte Character Set
上面的代码是使用Use Multi-Byte Character Set选项编译的,相应的编译ACE时也没有用到#define ACE_USES_WCHAR 1,如果使用Use Unicode Character Set是有问题的。要使写好的代码能同时在两个编译项中切换,除了利用ACE宏定义的ACE_TEXT,ACE_TString来处理字符串,用到的C++标准库string与stringstream时也需要做些处理。
1
#ifndef _SIDLE_APP_CONFIG_2
#define _SIDLE_APP_CONFIG_3

4
#include <vector>5
#include <string>6
#include <sstream>7
#include <boost/algorithm/string.hpp>8
#include <boost/lexical_cast.hpp>9
#include "ace/Configuration_Import_Export.h"10
using namespace std;11
using namespace boost;12

13
namespace TempfileManager14


{15
typedef basic_string<ACE_TCHAR, char_traits<ACE_TCHAR>,16
allocator<ACE_TCHAR> > stdstring;17
typedef basic_stringstream<ACE_TCHAR, char_traits<ACE_TCHAR>,18
allocator<ACE_TCHAR> > stdstringstream;19

20
struct WorkInfo21

{22
stdstring name; // 命名23
unsigned long interval; // 定时器间隔时间(秒)24
unsigned long timeout; // 定时器超时(秒)25
bool forceable; // 强制改变文件属性到普通26
bool recursiveable; // 递归处理子目录及下面的文件27
unsigned int hour; // 多少小时前的文件被处理 (小时)28
unsigned int num; // 每次最多处理文件数29
stdstring directory; // 目录30
stdstring pattern; // 通配符31
bool workable; // 是否交给定时器队列运行32
};33

34
class AppConfig35

{36
public:37

const vector<WorkInfo>& WorkList() const
{return _workList;}38

39
bool Open(ACE_TCHAR * inipath)40

{41
ACE_Configuration_Heap config;42
if(config.open() == -1)43

{44
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("config")), false);45
}46
ACE_Registry_ImpExp imp(config);47
if(imp.import_config(inipath) == -1)48

{49
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("Can't open config file")), false);50
}51
ACE_Configuration_Section_Key section;52
if(config.open_section(config.root_section(), ACE_TEXT("WorkList"), 0, section) == -1)53

{54
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("Can't open [WorkList] section")), false);55
}56
int index = -1;57
ACE_TString name;58
ACE_Configuration::VALUETYPE type;59
while(0 == config.enumerate_values(section, ++index, name, type))60

{61
if(type == ACE_Configuration::STRING)62

{63
ACE_TString value;64
if(config.get_string_value(section, name.c_str(), value) == -1)65

{66
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("item does not exist\n")), false);67
}68
69
stdstring str = value.c_str();70
WorkInfo item;71
vector<stdstring> splitVec; 72
split(splitVec, str, is_any_of(ACE_TEXT(",")));73
item.name = lexical_cast<stdstring>(trim_copy(splitVec[0]));74
item.interval = lexical_cast<unsigned long>(trim_copy(splitVec[1]));75
item.timeout = lexical_cast<unsigned long>(trim_copy(splitVec[2]));76
item.forceable = lexical_cast<bool>(trim_copy(splitVec[3]));77
item.recursiveable = lexical_cast<bool>(trim_copy(splitVec[4]));78
item.hour = lexical_cast<unsigned int>(trim_copy(splitVec[5]));79
item.num = lexical_cast<unsigned int>(trim_copy(splitVec[6]));80
item.directory = lexical_cast<stdstring>(trim_copy(splitVec[7]));81
item.pattern = lexical_cast<stdstring>(trim_copy(splitVec[8]));82
item.workable = lexical_cast<bool>(trim_copy(splitVec[9]));83
if(item.workable)84
_workList.push_back(item);85
}86
}87
return true;88
}89

90
const stdstring ToString()91

{92
stdstringstream ss;93
for(vector<WorkInfo>::iterator iter = _workList.begin(); iter != _workList.end(); ++iter)94

{95
ss << "work = " << iter->name << "\n";96
ss << "interval = " << iter->interval << "\n";97
ss << "timeout = " << iter->timeout << "\n";98
ss << "forceable = " << iter->forceable << "\n";99
ss << "recursiveable = " << iter->recursiveable << "\n";100
ss << "hour = " << iter->hour << "\n";101
ss << "num = " << iter->num << "\n";102
ss << "directory = " << iter->directory << "\n";103
ss << "pattern = " << iter->pattern << "\n";104
ss << "workable = " << iter->workable << "\n";105
ss << "\n";106
}107
return ss.str();108
}109

110
private:111
vector<WorkInfo> _workList;112
};113
}114
#endif1
[WorkList]2
;定时器名称(不可以有逗号)3
;定时器间隔(second)4
;定时器超时(second)5
;是否强制修改文件属性为普通(0:不处理, 1:处理)6
;是否递归处理(0:不递归, 1:递归)7
;多少小时前的被删除8
;一次最多处理多少个,9
;要处理的目录名10
;work是否提交给定时器运行11
"work_1"="clear D:/temp/qzx, 2, 10, 0, 0, 48, 1, D:/temp/qzx/, *.jpg, 1 "12

--
写配置文件注意:
1、写完最后一行要加回车换行
2、""="",等于号与引号之间不能有空格
原文链接:http://www.cnblogs.com/WuErPIng/archive/2005/06/23/179590.html

