SNMP管理系统器编程.docx
《SNMP管理系统器编程.docx》由会员分享,可在线阅读,更多相关《SNMP管理系统器编程.docx(15页珍藏版)》请在冰豆网上搜索。
SNMP管理系统器编程
一、课程设计目的以及要求
1)课程设计目的
随着网络规模的不断扩大,网络结构也变得越来越复杂。
用户对网络应用的需求不断提高,企业和用户对计算机网络的依赖程度也越来越高。
在这种情况下,企业的管理者和用户对网络的性能、运行状况以及安全性也越来越重视。
一个有效且实用的网络每时每刻都离不开网络管理。
网络管理是监督、组织和控制网络通信服务和信息处理所必需的各种活动的总称。
除了专门的标准化组织制定了一些标准外,一些网络发展比较早的机构与厂家也制定了一些在各自网络上应用的管理标准,其中应用最广泛的是简单网络管理协议(SimpleNetworkManagementProtocol,SNMP)。
SNMP是由IETF提出的面向Internet的管理协议,其管理对象包括网桥、路由器、交换机等存和处理能力有限的网络互连设备。
SNMP由于其简单性得到了业界广泛的支持,成为目前最流行的网络管理协议。
本课程设计的目的是通过编程实现SNMP协议,从而加深对SNMP协议的理解。
2)课程设计要求
熟悉SNMP协议后,按如下要求编写程序,实现SNMP协议,获取路由器中的相关信息。
A)采用VC6.0进行编程。
B)根据某路由器的IP及共同体名,获得该路由器的系统信息。
C)获取路由器的IP地址信息以及路由表信息;
2、原理分析
网管系统是指课管理真个网络及其中的网络设备的软件系统。
网管系统设计4个方面的容:
网管功能、资源、信息及结构。
其中,网管功能由ISO网络管理功能域定义:
网管资源的表示涉及资源的表示方法,主要包括网络中硬件,软件与服务等资源;网管信息的表示方法与传输方式,由网管系统采用的网络管理协议决定;网管系统的结构主要包括两层结构与三层结构。
SNMP网管系统采用客户机/服务器工作模式。
SNMP网管系统包括两个组成部分:
SNMP客户机与SNMP服务器。
其中,SNMP客户机是SNMP服务的请求者,他安装在网管管理工作站中,通常被称为SNMP管理器:
SNMP服务器是SNMP服务的响应者,它安装在支持SNMP服务的网络设备中,通常被称为SNMP代理。
管理信息保存在SNMP代理的MIB中。
SNMP服务在传输层采用UDP协议,在传输管理信息之前不需要先建立连接。
需要注意的是,SNMP代理主动发送Trap信息给SNMP管理器。
3、基本思路及关键问题的解决方法
显示相关信息
结束
开始
实例化CSnmp,并用IP和团体名初始化
调用CSnmp类中的Prepare函数,完成SNMP的加载、会话的建立等
填充请求列表,列表中存放的实际上是objectID
调用CSnmp类中的GetTable函数,根据请求列表查路由表信息,放到一个CRouter类里
释放资源
1)程序流程图
程序流程图如图1所示:
图1程序流程图
2)基本思路
首先,加载SNMP(包括SNMP主版本号、SNMP副版本号、支持的最高操作标准、默认的实体/上下文传输模式以及默认的重发机制);建立会话,在此过程中得到的会话句柄非常重要;设置传输模式SnmpSetTranslateMode和重传模式SnmpSetRetransmitMode,这两个函数的参数就是加载SNMP时使用的传输模式以及重发机制;创建实体HSNMP_ENTITY,第一个参数是步骤2中得到的句柄。
IP可以是发送消息的网络设备的IP地址或接收消息的管理设备的IP地址,通过需要具体创建实体——hSrcEntity、hDestEntity;对源实体和目的实体设置超时时间和重传次数——SnmpSetTimeout、SnmpSetRetry;建立上下文句柄——HSNMP_CONTEXT、hContext;建立变量捆绑列表;设置PDU格式,要正确发送数据必须采用特定的PDU格式;发送SNMP命令——SnmpSendMsg;接收SNMP响应;等到响应成功就释放资源。
3)关键问题及解决方案
1.如何设置PDU格式
PDU是SNMP数据包的一个部分,它包括请求标识符、错误状态、错误索引以及捆绑的变量名称。
因此设置PDU格式是此程序的关键部分。
HSNMP_PDUhPdu;
hPdu=SnmpCreatePdu(hSession,SNMP_PDU_GETNEXT,0,NULL,NULL,hVbl)
第二个参数是PDU类型,有多种操作方式:
SNMP_PDU_GETNEXT用来在不了解该表时获取第一个组值,SNMP_PDU_GET用来获得某个对象某个对象标识符的值;SNMP_PDU_SET用来修改某个对象标识符的值。
2.如何接收和响应SNMP
要接收和响应SNMP就先得创建实体,然后SNMP管理器调用函数,接收从SNMP代理返回的SNMP响应,SNMP管理器需要解析SNMP响应数据包,对各个字段逐个进行分析与判断,SNMP管理器需要分析错误类型字段,判断是否成功完成对管理对象的操作。
hSrcEntity=SnmpStrToEntity(hSession,(LPCSTR)GetLocalIP());
hDestEntity=SnmpStrToEntity(hSession,ip);
4、源代码
#include"winsock2.h"
#include"Winsnmp.h"
#include
#include
#include
#include
#pragmacomment(lib,"wsnmp32.lib")
#pragmacomment(lib,"ws2_32.lib")
usingnamespacestd;
typedefvectorstrvec;
typedefvectorstrvec_vec;
classCManager
{public:
CManager(stringstrIP,stringstrCommunity);//构造函数
~CManager();//析构函数
stringValueToString(smiVALUEsValue);//返回值转换
boolInitSnmp();//用于加载SNMP
boolSend(conststrvec&strOIDArray,smiINTsPDUType=SNMP_PDU_GETNEXT);
boolReceive(HSNMP_VBL&hVbl);//接收应答包
boolGetAValue(conststring&strOID,string&strResult);//获取ObjectID值
boolGetTable(strvecstrOIDArray,strvec_vec&strResultTable);
stringGetLocalIP();//获取本机IP地址
voidErrorMessage(stringstrMessage);//输出错误信息
voidSetEvent();
protected:
HSNMP_SESSIONm_hSession;//会话句柄
HSNMP_CONTEXTm_hContext;//上下文句柄
staticSNMPAPI_STATUSCALLBACKCallback
(
HSNMP_SESSIONhSession,//WinSNMP会话句柄
HWNDhWnd,//处理通知窗口的句柄
UINTwMsg,//窗口消息通知码
WPARAMwParam,//消息类型
LPARAMlParam,//PDU的请求标识符
LPVOIDlpClientData//可选的自定义数据
);
private:
smiUINT32m_nMajorVersion;//WinSNMPAPI主版本
smiUINT32m_nMinorVersion;//WinSNMPAPI副版本
smiUINT32m_nLevel;//支持最高的操作标准
smiUINT32m_nTranslateMode;//默认实体/上下文模式
smiUINT32m_nRetransmitMode;//默认的重发机制
stringm_IP;//IP地址
smiOCTETSm_Community;//团体名
HANDLEm_hEvent;
};
//构造函数
CManager:
:
CManager(stringstrIP,stringstrCommunity):
m_nMajorVersion(0),
m_nMinorVersion(0),
m_nLevel(0),
m_nTranslateMode(0),
m_nRetransmitMode(0),
m_IP(strIP)
{m_Community.len=strCommunity.length();
m_Community.ptr=newsmiBYTE[strCommunity.length()];
memcpy(m_Community.ptr,strCommunity.c_str(),strCommunity.length());
m_hEvent=CreateEvent(NULL,true,false,NULL);
}
//析构函数
CManager:
:
~CManager()
{SnmpFreeContext(m_hContext);
SnmpClose(m_hSession);
SnmpCleanup();
delete[]m_Community.ptr;
}
//SNMP初始化函数
boolCManager:
:
InitSnmp()
{
//加载SNMP
if(SnmpStartup(&m_nMajorVersion,&m_nMinorVersion,&m_nLevel,&m_nTranslateMode,&m_nRetransmitMode)==SNMPAPI_FAILURE)
{ErrorMessage("startupSNMPerror!
");
returnfalse;
}
//设置传输模式
if(SnmpSetTranslateMode(m_nTranslateMode)==SNMPAPI_FAILURE)
{ErrorMessage("Settransfermodeerror!
");
returnfalse;
}
//设置重传模式
if(SnmpSetRetransmitMode(m_nRetransmitMode)==SNMPAPI_FAILURE)
{ErrorMessage("Setretransmissionmodeerror!
");
returnfalse;
}
//建立会话
m_hSession=SnmpCreateSession(NULL,NULL,CManager:
:
Callback,(LPVOID)this);
if(m_hSession==SNMPAPI_FAILURE)
{ErrorMessage("Setconversationerror!
");
returnfalse;
}
//建立实体
HSNMP_ENTITYhEntity;
if((hEntity=SnmpStrToEntity(m_hSession,m_IP.c_str()))==SNMPAPI_FAILURE)
{ErrorMessage("Createntityerror!
!
");
returnfalse;
}
//建立上下文句柄
if((m_hContext=SnmpStrToContext(m_hSession,&m_Community))==SNMPAPI_FAILURE)
{ErrorMessage("Createcontexthandleerror!
!
");
returnfalse;
}
//设置超时时间
if(SnmpSetTimeout(hEntity,10)==SNMPAPI_FAILURE)
{ErrorMessage("Settimeouterror!
");
returnfalse;
}
//设置重传次数
if(SnmpSetRetry(hEntity,1)==SNMPAPI_FAILURE)
{ErrorMessage("Setretransmissionserror!
");
returnfalse;
}
returntrue;
}
//SNMP消息发送函数
boolCManager:
:
Send(conststrvec&strOIDArray,smiINTsPDUType)
{HSNMP_VBLhVbl;
HSNMP_PDUhPdu;
smiOIDsOid;
HSNMP_ENTITYhSrcEntity,hDestEntity;
//创建源主机和目的主机实体句柄
hSrcEntity=SnmpStrToEntity(m_hSession,GetLocalIP().c_str());
hDestEntity=SnmpStrToEntity(m_hSession,m_IP.c_str());
//创建变量绑定列表
if((hVbl=SnmpCreateVbl(m_hSession,NULL,NULL))==SNMPAPI_FAILURE)
returnfalse;
//点分十进制串转换成二进制格式
for(strvec:
:
const_iteratorit=strOIDArray.begin();it!
=strOIDArray.end();it++)
{SnmpStrToOid((*it).c_str(),&sOid);
SnmpSetVb(hVbl,0,&sOid,NULL);
}
//将数据转换成特定PDU格式
if((hPdu=SnmpCreatePdu(m_hSession,sPDUType,0,NULL,NULL,hVbl))==SNMPAPI_FAILURE)
returnfalse;
//发送PDU
if(SnmpSendMsg(m_hSession,hSrcEntity,hDestEntity,m_hContext,hPdu)==SNMPAPI_FAILURE)
returnfalse;
//释放句柄
SnmpFreeEntity(hSrcEntity);
SnmpFreeEntity(hDestEntity);
SnmpFreePdu(hPdu);
SnmpFreePdu(hVbl);
returntrue;
}
//SNMP消息接收函数
boolCManager:
:
Receive(HSNMP_VBL&hVbl)
{WaitForSingleObject(m_hEvent,INFINITE);
ResetEvent(m_hEvent);
HSNMP_ENTITYhSrcEntity;
HSNMP_ENTITYhDestEntity;
HSNMP_CONTEXThContext;
HSNMP_PDUhPdu;
//接收到消息
if(SnmpRecvMsg(m_hSession,&hSrcEntity,&hDestEntity,&hContext,&hPdu)==SNMPAPI_FAILURE)
returnfalse;
smiINTPDU_type;
smiINTerror_status;
smiINTerror_index;
//提取PDU中的数据
if(SnmpGetPduData(hPdu,&PDU_type,NULL,&error_status,&error_index,&hVbl)==SNMPAPI_FAILURE)
returnfalse;
returntrue;
}
//SNMP数值转换函数
stringCManager:
:
ValueToString(smiVALUEsValue)
{charcBuffer[1500];
memset(cBuffer,0,1500);
switch(sValue.syntax)
{caseSNMP_SYNTAX_NSAPADDR:
caseSNMP_SYNTAX_IPADDR:
sprintf(cBuffer,"%d.%d.%d.%d",sValue.value.string.ptr[0],sValue.value.string.ptr[1],sValue.value.string.ptr[2],sValue.value.string.ptr[3]);
break;
caseSNMP_SYNTAX_OPAQUE:
caseSNMP_SYNTAX_OCTETS:
if(sValue.value.string.len==0)
sprintf(cBuffer,"OCTETSNULL");
else
{memset(sValue.value.string.ptr+sValue.value.string.len,0,1);
sprintf(cBuffer,"%s",sValue.value.string.ptr);
}
break;
caseSNMP_SYNTAX_TIMETICKS:
intiHours,iMinutes,iSeconds;
longlUptime;
lUptime=sValue.value.uNumber/100;
iHours=(int)(lUptime/3600);
iMinutes=(int)((lUptime%3600)/60);
iSeconds=(int)((lUptime%60));
sprintf(cBuffer,"%d时,%d分,%d秒",iHours,iMinutes,iSeconds);
break;
caseSNMP_SYNTAX_INT:
sprintf(cBuffer,"%d",sValue.value.sNumber);
break;
caseSNMP_SYNTAX_UINT32:
caseSNMP_SYNTAX_CNTR32:
caseSNMP_SYNTAX_GAUGE32:
sprintf(cBuffer,"%U",sValue.value.uNumber);
break;
default:
sprintf(cBuffer,"NULL");
break;
}
returnstring(cBuffer);
}
//获得路由器信息函数
boolCManager:
:
GetAValue(conststring&strOID,string&strResult)
{HSNMP_VBLhVbl;
smiOIDsOIDRecv;
smiVALUEsValue;
intiCount;
strvecstrOIDArray;
strOIDArray.push_back(strOID+".0");
//发送请求列表string没有成功
if(!
Send(strOIDArray,SNMP_PDU_GET))
returnfalse;
//没有接收到应答
if(!
Receive(hVbl))
returnfalse;
//计算返回Vbl的行数
iCount=SnmpCountVbl(hVbl);
if(iCount!
=1)
{strResult="SnmpCounVblerror!
";
returnfalse;
}
//取返回结果
if(SnmpGetVb(hVbl,1,&sOIDRecv,&sValue)==SNMPAPI_FAILURE)
{strResult="SnmpGetVberror!
";
returnfalse;
}
strResult=ValueToString(sValue);
SnmpFreeVbl(hVbl);
returntrue;
}
//获得路由表信息函数
boolCManager:
:
GetTable(strvecstrOIDArray,strvec_vec&strResultTable)
{
longlIfEnd;
HSNMP_VBLhVbl;
smiOIDsOIDSend;
smiOIDsOIDRecv;
smiVALUEsValue;
intiCount,iOIDLen;
charcBuffer[100];
if(strOIDArray.empty())
returnfalse;
//计算OID标识符的长度
iOIDLen=count((strOIDArray[0]).begin(),(strOIDArray[0]).end(),'.')+1;
while(true)
{//发送请求列表string没有成功
if(!
Send(strOIDArray))
returnfalse;
//没有接收到应答
if(!
Receive(hVbl))
returnfalse;
//计算返回Vbl的行数
iCount=SnmpCountVbl(hVbl);
for(inti=0;i{//取返回结果
if(SnmpGetVb(hVbl,i+1,&sOIDRecv,&sValue)==SNMPAPI_FAILURE)
{ErrorMessage("获取结果失败!
");
returnfalse;
}
memset(cBuffer,0,100);
SnmpStrToOid(strOIDArray[i].c_str(),&sOIDSend);
SnmpOidToStr(&sOIDRecv,100,cBuffer);
strOIDArray[i]=string(cBuffer);
//判断格式是否一致,决定是否继续循环
SnmpOidCompare(&sOIDSend,&sOIDRecv,iOIDLen,&lIfEnd);
if(lIfEnd!
=0)
break;
strResultTable[i].push_back(ValueToString(sValue));
}
if(lIfEnd!
=0)
break;
}
SnmpFreeVbl(hVbl);
returntrue;
}
//获得本机地址函数
stringCManager:
:
GetLocalIP()
{charcHost[512];
PHOSTENTpHostI