peakzhang 发表于 2008-9-9 19:26:46

ACE的开发和使用 - FAQ

ACE的开发和使用
1 遇见的问题和解决方案
说明:

在遇见各种问题时候,首先查找说明文档,如ACE-INSTALL.HTM,里面往往已经包含了答案。

1.1.1   Console工程的崩溃问题
使用vs2003.net创建console工程后,使用ACE的类,初始化后,调试崩溃,而链接的LIB和使用的运行时DLL都是正确的。

A:是因为在stdafx.h里面包含了atlbase.h头文件,删除这一行或者转移到其它地方即可。

1.1.2   使用ACE_MAIN作为函数入口后,无法链接程序
A:调试版本加入aced.lib,发布版本加入ace.lib

1.1.3   编译错误:error C2039: “closesocket” : 不是“ACE_OS”的成员
A:包含 #include "ace/Asynch_Acceptor.h"

1.1.4   继承ACE_Asynch_Connector,编译时候失败,反馈HANDLER用法错误。
A:这个类的声明,必须和要作为模板参数写入的Service类写在一个.h文件内,是模板编译的问题。

1.1.5   MFC中使用ACE代码,启动即报告错误。
在使用ACE的任何代码之前,首先调用ACE::init()

1.1.6   静态连接的问题
静态连接ACE,链接失败。

在使用ACE的工程中,需要加入ACE_AS_STATIC_LIBS宏定义

1.1.7   使用ACE_InputCDR和ACE_OutputCDR的问题
在使用这两个类时候,发现要求输入输出的内容不是设想的内容,而是多出一些无用的字节。

是对齐的原因,调用ACE_CDR::mb_align()后,会使用8字节对齐,如果输入一个int型的数据,但是不在对齐的边界,ACE会自动调整位置,所以前面会多出来一些无用字节。解决方法是:调整协议规定,尽量避免使用长度+内容的协议格式,改用其它类型的规定,如XML;或者使用输出字符的办法,把长度内容当作字符输出

1.1.8   ACE调试符号的问题
使用动态调用ACE.DLL时候,工程调试无法看到dll内部的调用关系,比较麻烦。

这是因为在aced.dll目录下面,没有对应日期,对应版本的aced.pdb。如果没有找到这个文件,将无法显示正常的内容。日期版本等必须完全对应一致,才能使用调试符号。

还有,工程的项目设置,调试选项里面,还可以设置附加调试符号的路径。

1.1.9   直接使用IE进行非法数据的测试,是个不错的办法
打开IE,直接输入http://xxxx:port,IE会自己封装http的请求过来,对自定义协议来说肯定是非法数据,能够测试容错的能力。

1.1.10 想使用ACE_Time_Value来打印输出时间信息,无从下手
1、转换成为其它格式,如秒数,然后使用系统API进行格式化

2、直接使用调试宏,参数是%T或者%D,注意大写

1.1.11 使用ACE_Thread_Timer_Queue_Adapter引起系统死锁,DeadLock.
必须避免在ActiveTimer进行handle_timeout回调的时候,回调函数中又继续使用这个单件定时器,因为定时器的expire()方法,会锁住底层的数据,无法继续schedule定时器,因为schedule也需要锁定。这个时候,如果其它线程在某个公用函数中使用资源锁定,而在此函数中,继续调用schedule,handle_timeout的回调函数中,也需要取得这个资源,就会造成死锁。所以,处处单件的处理模式,往往造成难以想象到的冲突和问题。发生死锁时候,有比较好的办法来判断,使用PE,配置需要检查的程序的PDB到PE的Symbols目录,就能看到每个线程的上下文堆栈,发现调用的序列,从而判断出什么地方出了问题。

解决方法:

       把Actiev_Timer处理器分开,坚决避免这种循环调用。



1.1.12 Proactor框架中使用Timer造成系统异常的问题:
使用Proactor的框架,框架里面注册了重复的定时器,但是在处理器对象关闭的时候,会导致系统的崩溃,查看原因是内存对象访问冲突,因为销毁处理器对象的时候,并没有取消timer。

取消定时器操作,需要注意几个方面:

1、在主动关闭socket前取消一次。

2、退出清理时候取消一次,因为客户端有可能主动关闭连接,导致系统出错。

3、handle_read_stream会有多个线程在使用,注意潜在的数据读写竞争问题。_





2 框架部分
2.1    Reactor框架
2.1.1   :如何在多个线程中使用WFMO_Reactor?


2.1.2   在ACE_Task的svc函数中,使用ACE_Singleton对象,release版本造成崩溃。
2.1.3   使用异步的Connector和Acceptor
ACE_Asynch_Connector自动创建处理器,不要多个用户共享这个处理器,会造成混乱。

因为handler默认的处理策略,是delete this,而如果这个时候,其它用户刚好使用这个处理器,就会造成崩溃。

       比较好的策略是,一个请求一个handler,并且加上超时处理即可。

       还可以使用的办法:

1、使用同步的策略,避免异步处理的时序麻烦,在某些条件下,是很好的选择

2、使用单件的处理器共享策略。

3 平台部分
3.1    Linux平台的问题:
3.1.1   很简单的应用程序编译失败,无法找到需要包含的ACE文件
查看ACE携带的ACE-INSTALL.html,修改登录用户的脚本,.bash_profile,输出ACE_ROOT环境变量。

ACE_ROOT=xxxx

export ACE_ROOT

3.1.2   编译通过后,无法运行,找不到共享库文件
RedHat AS4下遇见此问题,默认ACE开发包代码安装在了/usr/local/src/ACE_Wrappers下面,这样,编译的时候,库文件被放置在了/usr/local/lib下,以致找不到。可以做的是:在/usr/src下编译代码,这样位置就正确了。

还可以这样,进入/etc/ld.so.conf.d/,复制里面一个文件,把其中文件的内容改成,/usr/local/lib,然后使用ldconfig命令运行一次,系统会自动更新。程序就可以正常运行了。

3.1.3   在linux下无法使用ACE_Dev_Poll_Reactor功能,链接失败
这个问题困扰我一个星期。我的平台是RedHat AS4,使用默认的内核安装编译ACE很顺利,但是没有办法使用epoll功能。初步想法是编译新内核,可是2.6的内核编译难度远远超过以往,10几次编译均告启动失败。后来仔细研究了一下为何ACE的脚本,configure在进行测试epoll_create的时候报告错误,把下载回来的config.log打开,把里面的测试代码编成一个cpp文件进行编译,居然报告是因为内核文件版本太低,无法使用!我马上明白了问题所在,问题在于,/usr/include/linux下面的文件都是2.4核心的文件,里面的version.h表明,版本是2.4的,如果使用这套文件进行编译,当然无法使用了。

使用Redhat AS4在/usr/src/kernels/下面的新文件,进行一下符号链接:

ln –sf /usr/src/kernels/2.6.9.22_EL.i386/linux /usr/include/linux

ln –sf /usr/src/kernels/2.6.9.22_EL.i386/asm /usr/include/asm

ln –sf /usr/src/kernels/2.6.9.22_EL.i386/scsi /usr/include/scsi

先提前给老的版本改名。

在进行处理后,configure报告错误了,无法进行处理,打开config.log仔细一查,居然是error没有定义,又发现了error.h没有找到。原来还有一个/usr/include/asm/error.h包含了<asm-gerneric/error.h>,而asm-gerneric没有定义,重新定义一个符号链接:

ln –sf /usr/src/kernels/2.6.9.22_EL.i386/asm-gerneric /usr/include/asm-gerneric

这时,configure通过了。可以进行make了。epoll_create创建成功。

问题还没完,这个时候去编译测试程序,测试程序使用了ACE_Dev_Poll_Reactor,结果仍然是失败,总是报告:undefined reference to ACE_Dev_Poll_Reactor。起初以为是无法找到链接库文件,因为按照ACE-install.html,编译的时候使用$ACE_ROOT/build目录,但是如果这样,库文件会放在: /usr/local/lib,总是无法找到。需要修改LD_LIBRARY_PATH,最后,发现如果直接在$ACE_ROOT/ace目录下使用make,库文件会放在正确的位置,但是仍然无法链接成功。

最后想到,Dev_Poll_Reactor这个文件编译需要定义ACE_HAS_EVENT_POLL宏,否则跳过,不编译。于是在config.h里面加入了#define ACE_HAS_EVENT_POLL,重新编译库,再重新编译测试文件,全部成功,运行正常。





4 经验部分:
4.1    关于可靠性:
可靠性是个模糊的概念,一般来说,做到100%的可靠,是非常困难的。比如断电、网络中断,都是异常事件。

不同的场合,对可靠性有不同的要求,有的时候,出错的情况,需要重新发送数据,重新确认。而有的时候,只需要检查是否有对应的数据返回。有的场合,直接给客户端返回错误就可以了。

[ 本帖最后由 peakzhang 于 2008-9-18 23:27 编辑 ]

caisirius 发表于 2008-9-16 16:20:47

什么意思?

ztenv 发表于 2011-3-15 13:03:04

不错,整理的很好,也学习一下;最初使用epoll的时候也遇到了这种情况
页: [1]
查看完整版本: ACE的开发和使用 - FAQ