DateAndTime是Snmpv2中的一种数据类型,它主要提供了对日期时间的描述。我在使用Snmp++开发包时,发现其不提供对DateAndTime类型的支持,而有时又需要用到该类型,于是,自己写了一个DateTime类扩展Snmp++。通过该类可以实现对DateAndTime类型的格式化,并且可以方便地提取各时间项。下面就对该类进行一下介绍。
要实现DateTime类,首先要要理解DateAndTime类型的定义。下面是RFC中对DateAndTime的定义:
DateAndTime ::= OCTET STRING (SIZE (8 | 11))
-- A date-time specification for the local time of day.
-- This data type is intended to provide a consistent
-- method of reporting date information.
--
-- field octets contents range
-- _____ ______ ________ _____
-- 1 1-2 year 0..65536
-- (in network byte order)
-- 2 3 month 1..12
-- 3 4 day 1..31
-- 4 5 hour 0..23
-- 5 6 minutes 0..59
-- 6 7 seconds 0..60
-- (use 60 for leap-second)
-- 7 8 deci-seconds 0..9
-- 8 9 direction from UTC "+" / "-"
-- (in ascii notation)
-- 9 10 hours from UTC 0..11
-- 10 11 minutes from UTC 0..59
--
-- Note that if only local time is known, then
-- timezone information (fields 8-10) is not present.
由定义可见,DateAndTime仍然是OCTET STRING类型的数据,只是对每个字节进行了具体的定义。比如前两个字节表示年,第五个字节表示小时等。所以如果某个开发包中没有DateAndTime类型,那么大可以用Octet类型去代替。但是这样做得到的只是一些无意义的乱码而已。因此,实现的关键就在于按照定义对特殊的Octet数据进行正确的解析。
既然DateAndTime也是Octet String,我们就通过Snmp++的OctetStr类继承得到类DateTime。这样,提取数据等底层工作都可以交给Snmp++,它会按照Octet String的得到方法原始数据。在Snmp++中,所有的SMI数据类型都有一个get_printable函数,它返回一个格式化好的字符串供程序打印输出等。该函数是一个虚函数,各个具体的类有不同的实现方法。如果我们直接调用OctetStr类的get_printable函数来输出DateAndTime类型数据,就会像前面所述的一样得到乱码,因此我们要重写该函数。另外,每个SMI数据类型类还有一个get_syntax函数,它返回一个32位整数,表示当前的数据类型的代码,它也是一个虚函数,同样需要重写。
下面我们来看一看DateTime类的定义:
#include "../snmp_include/octet.h"
#define sNMP_SYNTAX_DATETIME (aSN_APPLICATION | aSN_PRIMITIVE | 0x09)
/*this class implement the DateAndTime type defined in Snmpv2,
the oringinal snmp++ doesn't directly support this type*/
class DateTime:public OctetStr{
char format_str[128]; //保存格式化过后的时间字符串
int year;
int month;
int day;
int hour;
int minute;
int second;
int msecond;
public:
int get_year();
int get_month();
int get_day();
int get_hour();
int get_minute();
int get_second();
int get_msecond();
void format();
//the virtual function overwrite get_printble in class OctetStr
SmiUINT32 get_syntax();
char *get_printable();
};
其中format_str保存格式化过后的字符串,以后调用get_printable函数时都会返回这个字符串。其余数据项按其名字即知表示年月等时间项,并且都有一个对应的get函数来得到其值。#define sNMP_SYNTAX_DATETIME (aSN_APPLICATION | aSN_PRIMITIVE | 0x09)是对这个数据类型的代码的定义,一般来说,应该将这一行放在smi.h头文件中。定义了这个数字过后,就要修改get_syntax()函数,将其重载为:
SmiUINT32 DateTime::get_syntax()
{
return sNMP_SYNTAX_DATETIME;
}
在成员函数中,最重要的是format()函数,它将实现各时间项数据的解析和对原始字符串的格式化。下面是其实现:
void DateTime::format(){
//以下为提取时间数据
char *pbuf=(char *)this->data();
char buf[10];
for(int i=0; i<10; i++){
buf[i]=0;
}
strcpy( buf ,pbuf);
year=buf[0]*256+256+buf[1];
month=buf[2];
day=buf[3];
hour=buf[4];
minute=buf[5];
second=buf[6];
msecond=buf[7];
//以下为格式化字符串
int index=3;
int temp=year;
for(; index>=0; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[4]='-';
index=6;
temp=month;
for(; index>=5; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[7]='-';
index=9;
temp=day;
for(; index>=8; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[10]=',';
index=12;
temp=hour;
for(; index>=11; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[13]=':';
index=15;
temp=minute;
for(; index>=14; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[16]=':';
index=18;
temp=second;
for(; index>=17; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[19]='.';
index=21;
temp=msecond;
for(; index>=20; index--){
format_str[index]=48+(temp-temp/10*10);
temp/=10;
}
format_str[22]=0;
}
在处理过程中,由于各位字节就是一个数字,所以处理也比较简单,只需直接将对应字节赋值给其所表示的数字即可,比如要得到月就用month=buf[2]。只有处理年的时候稍有不同,因为年是由两个字节表示,所以要用高位字节乘256再加低位字节,处理语句为year=buf[0]*256+256+buf[1]。
标准的时间输出格式应该为YYYY-MM-DD,HH:MM:SS.MM形式,因此经过处理过后的format_str字符串中将存储这种格式的时间字符串。具体将数字转化为字符的代码见上面,这里就不再解释了。要说明的是对于这段代码可以用数字字符串转换函数将其简化。
处理完数据后,就可以重载get_printable()函数了,因为不能确定每次调用该函数时数据是否已经更新,所以在返回值之前都要先调用format格式化一下。
char *DateTime::get_printable()
{
format();
return format_str;
}
由此,我们就得到了一个比较完整的DateTime类。经测试,证明能正确运行。比如下面是我得到的某台机器上软件安装表的一行数据:
hrSWInstalledIndex:41
hrSWInstalledName:Java 2 SDK, SE v 1.4.2 _01
hrSWInstalledType:4
hrSWInstalledDate: 2004-07-01 ,19:29:50.00
可见,使用该类就可以正确地解析DateAndTime类型的数据。通过扩展,我们还可以生成更多的Snmp++不直接支持的数据类型,这也是面向对象技术中继承特性带给我们的好处之一吧。