版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
[url]http://egeho123.blogbus.com/logs/5564119.html[/url]

摘 要  ACE自适配通信环境(Adaptive Communication Environment)是一种面向对象(OO)的工具包,它实现了通信软件的许多基本的设计模式。ACE的目标用户是在UNIX和Win32平台上开发高性能通信服务和应用的开发者。ACE简化了使用进程间通信、事件多路分离、显式动态链接和并发的OO网络应用和服务的开发。通过在运行时将服务与应用动态链接进应用,并在一个或多个进程或线程中执行这些服务,ACE使系统的配置和重配置得以自动化。  本论文描述ACE的结构和功能,并使用来自像电信、企业级医学成像和WWW服务这样的领域的例子阐释核心的ACE特性。ACE可以自由使用,并正在被用于许多商业项目(比如爱立信、Bellcore、西门子、摩托罗拉、柯达,和McDonnell Douglas),以及许多学院和工业研究项目。ACE已被移植到多种OS(操作系统)平台上,包括Win32和大多数的UNIX/POSIX实现。此外,同时有C++和Java版本的ACE可用。
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
[url]http://egeho123.blogbus.com/logs/19600815.html[/url]

ACE 是一个很大的东西,每个人学习路径可能都不一样。我的方法首先阅读 C++ Network Programming, Volume 1 ,让自己明了ACE 的设计思路;再从实际的小项目入手,逐步的用 ACE 内容替换掉自己的东西,在比较和实践之间求得较深的了解。
     就一个正常项目而言,一个配置文件是必不可少的,那就先从这里入手了。linux/unix 程序可能经常用到命令行方式,不过我还是比较喜欢 windowsini 格式的,当然,有xml 的更好,不过 ACE 里暂时没有提供。配置文件的使用很简单,ACE 提供的类也很友好。在这里主要是整理一些细节,让大家不在这里浪费太多时间。
 
  
 1、ACE 配置类简介与使用
 
   先给出一个印象(为了直指主题,所有错误处理都被清除,具体例子请看最后源码): 
ACE简介_职场    ACE_Configuration_Heap config; 
        config.open();
ACE简介_职场     ACE_Registry_ImpExp impExp(config);    
// win32的注册表导出格式
ACE简介_职场     
//ACE_Ini_ImpExp impExp(config);          // windows的.ini格式,注意读出来的都是字符串,类型需要自己转换
ACE简介_职场
     impExp.import_config(ACE_TEXT("配置文件名"));    // 读取配置文件 
ACE简介_职场
 
ACE简介_职场     ACE_Configuration_Section_Key section;
// 指向一个配置节section
ACE简介_职场
     config.open_section(config.root_section(), ACE_TEXT("节名"), 0, section);
ACE简介_职场 
ACE简介_职场     
// 读取字符串
ACE简介_职场
     ACE_TString str;   
ACE简介_职场     config.get_string_value(section, ACE_TEXT(
"键名"), str); // ACE_Ini_ImpExp,只能使用这一种方法
ACE简介_职场 
ACE简介_职场    
// 读取整型
ACE简介_职场
     u_int i;
ACE简介_职场     config.get_integer_value(section, ACE_TEXT(
"键名"), i);
ACE简介_职场 
ACE简介_职场    
// 读取二进制
ACE简介_职场
     void * data_out = 0// 最好使用智能指针
ACE简介_职场
     size_t length = 0;
ACE简介_职场     config.get_binary_value(section, ACE_TEXT(
"键名"), data_out, length);
ACE简介_职场     delete []data_out;
    可以浏览一下 ACE_Configuration_Heap 和 ACE_Ini_ImpExp 或 ACE_Registry_ImpExp 之间的关系。不需要套上术语来理解,简化一下代码对此很有帮助
 
 一个超简化的ACE_Configuration_Heap

1ACE简介_职场 class ACE_Export ACE_Configuration_Heap : public ACE_Configuration
2ACE简介_职场_23 ACE简介_简介_25{
3ACE简介_休闲_26  // 其它函数全部略去
4ACE简介_休闲_26  private:
5ACE简介_休闲_26    SECTION_MAP *index_;
6ACE简介_职场_29 }
;
 值得注意的是 ACE_Registry_ImpExp 和 ACE_Ini_ImpExp ,这两个类都继承自 ACE_Config_ImpExp_Base,分别处理不同的格式。
 
 简化版本的 ACE_Config_ImpExp_Base, 具体实现请看 Configuration_Import_Export.h
1ACE简介_职场 class ACE_Config_ImpExp_Base
2ACE简介_职场_31 ACE简介_简介_25{
3ACE简介_休闲_26  public:
4ACE简介_休闲_26   ACE_Config_ImpExp_Base (ACE_Configuration& config);
5ACE简介_休闲_26   virtual int import_config (const ACE_TCHAR* filename) = 0;  // 从文件中导入配置
6ACE简介_休闲_26   virtual int export_config (const ACE_TCHAR* filename) = 0;  // 导出配置到文件 
7ACE简介_休闲_26  protected:
8ACE简介_休闲_26   ACE_Configuration &config_;
9ACE简介_职场_29 }
;

 从两个简化的类,可以想象 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 注册表文件导出文件格式,格式如下:


ACE简介_职场  [Section]
ACE简介_职场          
"key"="String Data"
ACE简介_职场          
"key"=dword: 十六进制数值
ACE简介_职场          
"key"=hex: 二进制
ACE简介_职场          注意,二进制的写法如下 
ACE简介_职场          
"pwd"=hex:31,32,33,34,35,36,37,38

 2.2. ACE_Ini_ImpExp

 从文件中导入字符串配置数据。充许 not-typed 值(没有 #,dword: hex:, 等前缀),在标准的.ini和.conf中跳过空白字符(tabs和spaces)。 值 (在等式的右边)可以被双引号限定,使得tabs或spaces能够留在字符串中。调用者必须自己转换字符串到类型。格式如下:
ACE简介_职场 TimeToLive     =    100
ACE简介_职场 Delay          
=    false
ACE简介_职场 Flags          
=    FF34  # 可以象这样写注释
ACE简介_职场 Heading        
=    "ACE - Adaptive Communication Environment"
  
 3、一个友好的函数

     使用此类配置文件时,如果用到会变化的配置集合,我们经常遇到这样的写法
ACE简介_职场 [section]
ACE简介_职场 
"size"=dword:2
ACE简介_职场 
"item_1"="value1"
ACE简介_职场 
"item_2"="value2"

     这样写因为 window 提供的 API 只能一项一项读取,我们只能在读取了size 的值后,才能拼凑出"item_1"键名来取到相应的值。在实际操作中维护人员很容易遗漏操作,增加了选项但忘记增加size的值。ACE则提供了非常友好的enumerate_values函数,配合一下 boostsplit 使用起来感觉很好。
 
     一个非常简单的TCP转发程序的配置文件,将一端口接收到的数据转发至指定地址的端口,可以开多个服务端口:
ACE简介_职场 [server\listen_items]
ACE简介_职场 ;listen_port, target_ip, target_port, timeout (second), validate
ACE简介_职场 
"item_1"="19998,192.168.168.217,8101,60,1"
ACE简介_职场 
"item_2"="8000, 192.168.0.57, 23, 60, 1"
        实际的代码摘录,但不一定能编译呵 :-)  
 1ACE简介_职场 
 2ACE简介_职场 #include <boost/algorithm/string.hpp>
 3ACE简介_职场 #include <boost/lexical_cast.hpp>
 4ACE简介_职场 using namespace boost;
 5ACE简介_职场
 6ACE简介_职场 
 7ACE简介_职场 class ListenItem
 8ACE简介_休闲_66 ACE简介_简介_25{
 9ACE简介_休闲_26 public:
10ACE简介_休闲_26  unsigned int listen_port_; 
11ACE简介_休闲_26  string target_ip_;    
12ACE简介_休闲_26  unsigned int target_port_; 
13ACE简介_休闲_26  unsigned int timeout_;    
14ACE简介_休闲_26  bool validate_;     
15ACE简介_职场_29 }
;
16ACE简介_职场
17ACE简介_职场 vector<ListenItem> vec;
18ACE简介_职场 
19ACE简介_职场 int index = -1;
20ACE简介_职场 ACE_TString name;
21ACE简介_职场 ACE_Configuration::VALUETYPE type;
22ACE简介_职场 while(0 == config.enumerate_values(section, ++index, name, type))
23ACE简介_职场_83 ACE简介_简介_25{
24ACE简介_休闲_26  ACE_TString str;
25ACE简介_休闲_26  if(config.get_string_value(section, name.c_str(), str) == -1)
26ACE简介_职场_88  ACE简介_简介_25{
27ACE简介_休闲_26   ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("ListenPort item does not exist\n")), -1);
28ACE简介_职场_92  }

29ACE简介_休闲_26
30ACE简介_休闲_26  ListenItem item;
31ACE简介_休闲_26  vector<string> splitVec; 
32ACE简介_休闲_26  string ss = str.c_str();
33ACE简介_休闲_26  split( splitVec, ss, is_any_of(",") );  
34ACE简介_休闲_26  item.listen_port_ = lexical_cast<unsigned int>(trim_copy(splitVec[0]));
35ACE简介_休闲_26  item.target_ip_ = lexical_cast<string>(trim_copy(splitVec[1]));
36ACE简介_休闲_26  item.target_port_ = lexical_cast<unsigned int>(trim_copy(splitVec[2]));
37ACE简介_休闲_26  item.timeout_ = lexical_cast<unsigned int>(trim_copy(splitVec[3]));
38ACE简介_休闲_26  item.validate_ =  lexical_cast<bool>(trim_copy(splitVec[4]));
39ACE简介_休闲_26  if(item.validate_)
40ACE简介_休闲_26   vec.push_back(item);
41ACE简介_休闲_26
42ACE简介_职场_29 }

43ACE简介_职场 
44ACE简介_职场
45ACE简介_职场
 
  这样就可以不写

1ACE简介_职场stringstream s;
2ACE简介_职场 s << "item_" << i+1;
3ACE简介_职场
     这样的代码了,也避免了维护人员遗漏操作

     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时也需要做些处理。
ACE简介_ACE_114完整源码示例
  1ACE简介_简介_115#ifndef _SIDLE_APP_CONFIG_
  2ACE简介_简介_115#define _SIDLE_APP_CONFIG_
  3ACE简介_简介_115
  4ACE简介_简介_115#include <vector>
  5ACE简介_简介_115#include <string>
  6ACE简介_简介_115#include <sstream>
  7ACE简介_简介_115#include <boost/algorithm/string.hpp>
  8ACE简介_简介_115#include <boost/lexical_cast.hpp>
  9ACE简介_简介_115#include "ace/Configuration_Import_Export.h"
 10ACE简介_简介_115using namespace std;
 11ACE简介_简介_115using namespace boost;
 12ACE简介_简介_115
 13ACE简介_简介_115namespace TempfileManager
 14ACE简介_职场_128ACE简介_休闲_130{
 15ACE简介_ACE_131    typedef basic_string<ACE_TCHAR, char_traits<ACE_TCHAR>,
 16ACE简介_ACE_131        allocator<ACE_TCHAR> > stdstring;
 17ACE简介_ACE_131    typedef basic_stringstream<ACE_TCHAR, char_traits<ACE_TCHAR>,
 18ACE简介_ACE_131        allocator<ACE_TCHAR> > stdstringstream;
 19ACE简介_ACE_131
 20ACE简介_ACE_131    struct WorkInfo
 21ACE简介_职场_137    ACE简介_休闲_130{
 22ACE简介_ACE_131        stdstring name;    // 命名
 23ACE简介_ACE_131        unsigned long interval;    // 定时器间隔时间(秒)
 24ACE简介_ACE_131        unsigned long timeout;    // 定时器超时(秒)
 25ACE简介_ACE_131        bool forceable;    // 强制改变文件属性到普通
 26ACE简介_ACE_131        bool recursiveable;    // 递归处理子目录及下面的文件
 27ACE简介_ACE_131        unsigned int hour;        // 多少小时前的文件被处理 (小时)
 28ACE简介_ACE_131        unsigned int num;        // 每次最多处理文件数
 29ACE简介_ACE_131        stdstring directory;        // 目录
 30ACE简介_ACE_131        stdstring pattern;        // 通配符
 31ACE简介_ACE_131        bool workable;    // 是否交给定时器队列运行
 32ACE简介_休闲_150    }
;
 33ACE简介_ACE_131
 34ACE简介_ACE_131    class AppConfig
 35ACE简介_休闲_153