由于公司项目的需要,需要将采集器c++代码在Red hat不同版本操作系统移植,出现了好多问题,所以写此文来做一次全面的总结。
首先现介绍一些采集器的功能:
- 响应Server服务器的请求;
- 维护访问物理设备的信息;
- 使用snmp协议周期地访问物理设备,获取需要地数据;
- 存入数据库。
采集器运行的环境:
- 编程语言 :C++
- 操作系统 :RHAS2.1 ,RH9.0,RHAS4.4
- 编译器 :gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) 和 gcc version 3.4.6 20060404 (Red Hat 3.4.6-3) ,gcc version 2.96 20000731 (Red Hat Linux 7.2 2.96-108.1)
采集器使用的第三方开发包:
- log4cpp-0.3.5rc3 : 写log日志开发包
- net-snmp-5.2.1 : snmp开发包
- unixODBC-2.2.11 : sqlserver2k访问sql接口
- freetds-0.64-stable : sqlserver2k访问sql接口
- ACE : 跨操作系统C++开发平台
- snmp++ : snmp开发包
- expat : expat 是解析xml配置文件的api
在不同操作系统移植时,出现问题最多的是第三方开发包的移植,
例如
:
在平台
RHAS2.1
下,只能使用
ACE5.4.1
和
log4cpp-0.3.5rc3zdsmodi.tar
开发包,否则编译不成功;
在平台
RH9.0
下,只能使用
ACE5.4.1
和
log4cpp-0.3.5rc3.tar.gz
开发包,否则编译不成功;
在平台
RHAS4.4
下,可以使用
ACE5.5
和
log4cpp-0.3.5rc3.tar.gz
开发包;
自己开发的代码由于按照
c
++标准开发的,基本上是重新编译即可。
现总结如下:
一、使用的日志开发包是通过修改得到的,由于早期是使用
RHAS2.1
操作系统,高版本的
log4cpp-0.3.5rc3
不支持,低版本也不支持。自己是从网上找到
dedian
的
log4cpp
日志的
.cpp, .h
源文件,复制到
log4cpp-0.3.5rc3
目录下,居然编译通过,而且还能使用
api
写
log
日志了。这真是幸运呀。以后运行平台都使用
RHAS4.4
和
RH9.0
,可以使用高版本的
log4cpp-0.3.5rc3
。
二、使用
net-snmp-5.2.1
主要是用来在
linux
机上启动
snmpd
守候进程,采集器来读取
pc
机上的一些配置信息。
在
red hat 9
平台下
net-snmp
在编译会出问题:
/usr/bin/ld: cannot find -lelf
,
那么需要装两个
rpm bzip2-devel-1.0.2-8.i386.rpm
,
elfutils-devel-0.76-3.i386.rpm
,重新编译即可。
在
Red hat as4,4
平台下,
编译会出错,报
/usr/lib/libpopt.so: could not read symbols: File in wrong format
将各个 Makefile 文件中对应的 popt 去掉,重新编译就可以通过。
将各个 Makefile 文件中对应的 popt 去掉,重新编译就可以通过。
三、
sqlserver2k
访问
sql
接口包
unixODBC-2.2.11
和
freetds-0.64-stable
,是用来在
linux
平台访问
windows
平台下的
sqlserver2k
数据的开发包,在移植操作系统的时候,出现使用开发包自带的
tsql
或
isql
命令访问数据库能够正常访问,带使用程序使用对应的
api
老是报登陆不正确的错误提示,原因是用户名,密码编码的问题,要使用以下语句才可以:
char *charset = NULL;
setlocale(LC_ALL, "");
char* locale = setlocale(LC_ALL, NULL);
DBSETLCHARSET(mLogin,"ISO-8859-1" );
DBSETLNATLANG(mLogin, "us_english");
setlocale(LC_ALL, "");
char* locale = setlocale(LC_ALL, NULL);
DBSETLCHARSET(mLogin,"ISO-8859-1" );
DBSETLNATLANG(mLogin, "us_english");
还有一个隐患,就是高版本的
sqlserver
数据库有可能不在支持
tds
协议访问数据库,以后的可能会有问题
四、
SNMP++
是我最熟悉的
snmp
协议的
api
,不过是第一次在
linux
使用,有些代码比如
snmpget
等操作还不能编译通过,还有
makefile
也写的不好,需要重新整理,主要是没有时间。
五、在移植时不同的编译器在编译也会出问题,在编译器
gcc3.2.2
,主要是使用
var-args.h
的函数如
var_start,var_end
,而
RHAS4.4
使用的是
gcc3.4.6,
其使用的是
c
++标准的函数库
std-args.h
,不在支持
var-args.h
的函数,所以需要移植,移植代码仅仅举如下例子说明就明白了。这主要是代码没有严格按照
标准的
c
++来编写而造成的问题。
在
RHAS2.1
和
RH9
。
0
使用的
gcc3.2.2
,其代码是:
#include <varargs.h>
int getAllElemText(XmlFile,NodeName,va_alist)
char *XmlFile ;
char *NodeName ;
va_dcl
{
char *pNodeName ;
va_list ap;
int j;
va_start(ap);
for(j=0;;j++)
{
pNodeName = va_arg(ap,char *);
if(!pNodeName)
break;
#ifdef DEBUG
printf("NO:[%d]pNodeName=[%s] /n",j,pNodeName);
#endif
}
va_end(ap);
return 0;
}
char *XmlFile ;
char *NodeName ;
va_dcl
{
char *pNodeName ;
va_list ap;
int j;
va_start(ap);
for(j=0;;j++)
{
pNodeName = va_arg(ap,char *);
if(!pNodeName)
break;
#ifdef DEBUG
printf("NO:[%d]pNodeName=[%s] /n",j,pNodeName);
#endif
}
va_end(ap);
return 0;
}
在
RHAS4.4
的
gcc3.4.6
只支持
std-arg.h,
所以其对应的代码如下:
#include <stdarg.h>
int getAllElemText(char* XmlFile,char* NodeName, ...)
{
char *pNodeName ;
va_list ap;
int j;
va_start(ap,NodeName);
for(j=0;;j++)
{
pNodeName = va_arg(ap,char *);
if(!pNodeName)
break;
int getAllElemText(char* XmlFile,char* NodeName, ...)
{
char *pNodeName ;
va_list ap;
int j;
va_start(ap,NodeName);
for(j=0;;j++)
{
pNodeName = va_arg(ap,char *);
if(!pNodeName)
break;
#ifdef DEBUG
printf("NO:[%d]pNodeName=[%s] /n",j,pNodeName);
#endif
}
va_end(ap);
return 0;
}
printf("NO:[%d]pNodeName=[%s] /n",j,pNodeName);
#endif
}
va_end(ap);
return 0;
}
在
gcc3.2
中,下面代码是能编译通过,并且能正常运行
unsigned int pos = mPacketStr.find_first_of(":");
if(pos == string::npos)
{
CFileLog::Instance()->log(getpid(),"CAPPResponse","parse","response has not : char",CFileLog::INFO);
return 1;
}
if(pos == string::npos)
{
CFileLog::Instance()->log(getpid(),"CAPPResponse","parse","response has not : char",CFileLog::INFO);
return 1;
}
但是在
gcc3.4.6
中,虽然能够编译通过,但是出警告错误:
warning: comparison is always true due to limited range of data type
,
要把上面的代码改成这样才可以:
string::size_type pos = mPacketStr.find_first_of(":");
if(pos == string::npos)
{
CFileLog::Instance()->log(getpid(),"CAPPResponse","parse","response has not : char",CFileLog::INFO);
return 1;
}
if(pos == string::npos)
{
CFileLog::Instance()->log(getpid(),"CAPPResponse","parse","response has not : char",CFileLog::INFO);
return 1;
}
五、
ACE
使用出的问题最多。
在
RHAS2.1
平台下,高版本的
ace
不能在其上编译,最高只支持
ace5.4.1
版本的,惨呀,但是花了好长时间试图编译成功,实在不行了,在网上满地的找原因,才在一个
ace
商用支持的网站发现
RHAS2.1
最高只支持
ace5.4.1
版本的,我那个郁闷呀。
在
RH9.0
平台下,高版本的
ace5.5
不能在其上编译
,
只能使用
ace5.4.1
版本的
而在
RHAS4.4
平台下,
ace5.4.1
居然又编译不过了,这次我学乖了,首先在网上看发现,
RHAS4.4
平台下最低只能支持
ace5.4.7
的,原来的又废了,一横心下了最高版本的
ace5.5
,在
ace
目录下
%mkdir build
%cd build
%make
%cp /home/creco/ats/ACE_wrappers/build/ace/.libs/* /home/creco/ats/ACE_wrappers/lib
%mkdir build
%cd build
%make
%cp /home/creco/ats/ACE_wrappers/build/ace/.libs/* /home/creco/ats/ACE_wrappers/lib
我没有使用
make install
进行安装只是将库文件拷贝到一个我程序能够找的目录,谁想我的代码老是报
ace
的错误,找了好长时间才发现问题,发现是在
ace
目录下没有找到对应的
config.h
文件,可以在编译的目录下
build/ace
拷贝到
ACE_ROOT/ace
目录下即可。