11、要想将数据正确的发送到目的地,我们必须其按照特定的格式来发送,对于了解ip协议的编程(www.cppentry.com)人员来说,就不需要做过多地解释了。我们用函数
HSNMP_PDU SnmpCreatePdu( HSNMP_SESSION session, // handle to the WinSNMP session smiINT PDU_type, // PDU type smiINT32 request_id, // PDU request identifier smiINT error_status, // valid only for SNMP_PDU_GETBULK requests smiINT error_index, // valid only for SNMP_PDU_GETBULK requests HSNMP_VBL varbindlist // handle to the variable bindings list ); |
来完成该功能。
第一个和最后一个参数是我们上面构造的会话句炳和变量绑定列表句炳,第二个参数很重要,他表示我们想要执行的操作方式,SNMP中有如下的选项:
SNMP_PDU_GET SNMP_PDU_GETNEXT SNMP_PDU_RESPONSE SNMP_PDU_SET SNMP_PDU_V1TRAP SNMP_PDU_GETBULK SNMP_PDU_TRAP |
对于这些操作,我建议读者最好找点有关书籍看看,在这里我只对部分操作大概讲解一下,SNMP_PDU_GET通常用来获得某一个特定的对象标志符所对应的值,SNMP_PDU_GETNEXT是在编程(www.cppentry.com)人员不了解该表列情况下使用的用来获取一组值的操作。SNMP_PDU_RESPONSE一般是SNMP代理填写的,表示应答发出操作请求的数据报。SNMP_PDU_SET是用来改变某一对象标志符的值的操作。SNMP_PDU_GETBULK只能在V2版本以上使用,是用来解决SNMP_PDU_GETNEXT一次消息只能取得一个数据的缺点,可通过发一次消息取得一组数据。SNMP_PDU_V1TRAP和SNMP_PDU_TRAP使用来发自陷消息的操作。
第三个参数request_id,对于同步实现消息机制的编程(www.cppentry.com)来说,几乎没有作用,但是对于异步操作,该参数有很重要的作用,你可以用它来标志某一个请求的消息,如果有几个消息都在消息队列中,你可以通过它来确定自己想要处理的消息,该值完全可以自己来设定。
error_status和error_index在SNMP_PDU_GETBULK操作中分别为PDU中non_repeaters域定一个值和PDU的max_repetitions域指定一个值。
在其他操作中都为0。
该函数返回一个PDU句炳。
万事俱备了,就让我们的火车启航吧。用下面的函数
12、 SNMPAPI_STATUS SnmpSendMsg( HSNMP_SESSION session, // handle to the WinSNMP session HSNMP_ENTITY srcEntity, // handle to the source entity HSNMP_ENTITY dstEntity, // handle to the target entity HSNMP_CONTEXT context, // handle to the context HSNMP_PDU PDU // handle to the PDU );
看看这些参数,是不是我们都已经创建过了,添上他们。
以上就是整个发送过程,我们再来理顺一下,1。加载SNMP,2。建立会话,3。设置传输模式,4。创建实体,5。设置重传模式,6。设置超时时间,7。设置重传次数,8。创建上下文句炳,9。创建变量捆绑列表,10。追加绑定列表,11。创建PDU,12。发送消息。当然你如果只须获得一个数据,那么第10步就不需要了。
接下来我们要接收消息,并处理他们。
1、接收消息,用函数
SNMPAPI_STATUS SnmpRecvMsg( HSNMP_SESSION session, // handle to the WinSNMP session LPHSNMP_ENTITY srcEntity, // handle to the source entity LPHSNMP_ENTITY dstEntity, // handle to the target entity LPHSNMP_CONTEXT context, // handle to the context LPHSNMP_PDU PDU // handle to the PDU ); |
声明一下,该函数的参数和SnmpSendMsg好像是一样的,不错,但参数的进出不一样,SnmpRecvMsg除第一个参数是我们创建过的以外,其他参数都是输出参数,就是用来接收的参数,好像很爽的样子,因为只需自己设定一个参数,其他的声明一个变量,只管接收就行了。仔细想想,还挺对应的呢!
2、提取数据报,用函数
SNMPAPI_STATUS SnmpGetPduData( HSNMP_PDU PDU, // handle to the PDU smiLPINT PDU_type, // PDU_type field of the PDU smiLPINT32 request_id, // request_id field of the PDU smiLPINT error_status, // error_status field of the PDU smiLPINT error_index, // error_index field of the PDU LPHSNMP_VBL varbindlist // handle to the variable bindings list ); |
也很爽,只有第一个参数是需要你输入的,而这已经通过SnmpRecvMsg得到了,其他的参数都是需要接收的,看到什么了,对了,request_id,如果你才用异步接收的话,它可很重要的啊,可以帮你标识发送的消息。还有error_status和error_index,记得吗,用在SNMP_PDU_GETBULK操作中,他们的意义是不同的,除此之外,他们用来接收SNMP端返回的错误消息,如果返回全都是0,那就是正确返回了,如果不是,那你就的查一查他们所代表的意思了,一般的SNMP书上都会有介绍。
3、计算返回列表数目,用函数
SNMPAPI_STATUS SnmpCountVbl( HSNMP_VBL vbl // handle to the variable bindings list ); |
将你上一步得到的varbindlist代到里面去就行了,他的返回只是一个整型,使你所得到的变量绑定列表返回的变量数。
4、取得返回结果,用函数
SNMPAPI_STATUS SnmpGetVb( HSNMP_VBL vbl, // handle to the variable bindings list smiUINT32 index, // position of the variable binding entry // in the list smiLPOID name, // pointer to the structure to receive the // variable name smiLPVALUE value // pointer to the structure to receive the // associated value ); |
既然在上一步已经得到了结果数,用一个简单的for循环一次将结果取出吧。该函数有四个参数,第一个在第三步已得到,第二个就是你for循环中的变量值,记住取得变量是从0开始的,后两个参数想想是不是与前面某个函数的参数有点相似。对了,前面我们把他们都置为空,现在SNMP代理将返回值添了进去,我们可以坐享其成了,定义两个变量,接收就行了。提醒一下,对ip地址的接收会有点不同,因为返回值将其封装为一个指针数组了,你需要一个一个的取出来!
看上去工作是做完了,别急,还有一个很重要的环节,难道你没想过创建了这么多东西就不会占用资源吗?当然要占用,而且你不释放他它不会自动释放,前面我们总共介绍了5个重要的句炳,只有会话句炳是在发送和接收消息时都用到的,所以在发送和接收消息以后,你要将其他四个句炳释放掉,那么会话句炳何时释放呢?对了,应该在你应用程序退出的过程中释放掉,进而你会想到创建会话句炳的位置了吧,那就是在构造函数里。以上这些释放句炳资源的函数SNMP API都有提供,如SnmpFreeEntity,SnmpFreeContext,SnmpFreeVbl,SnmpFreePdu,SnmpClose,他们的参数只有一个,就是你要是放得句炳。最后你要清理整个现场,用函数SnmpCleanup()解决他们吧。
一且到此完结,大概步骤就这些了,你也许对SNMP_PDU_SET和SNMP_PDU_TRAP有些不解,前者你可以在第10步追加绑定列表中改变变量值,当然要遵循smiVALUE的结构,将类型和值都添上,填好需要改变的对象标志符,同时在第11步创建PDU中将类型设为SNMP_PDU_SET就行了。
对于想进行SNMP编程(www.cppentry.com)的人员,在下以菜鸟的身份给你们提个醒,SNMP编成的过程很死,但精心的设计会使你的程序更加的健壮、高效和容易扩展,我强烈的建议你们看看hp的snmp++,他的源代码很有层次,极易扩展
|