Windows下的net-snmp库,c++(Qt)编译使用(附带源码)

一.Windows下要想使用snmp协议读取设备数据,必须先开启snmp服务,开启过程参考以下网站:

windows开启snmp协议(windows server、windows11、windows 低版本)-CSDN博客

二.net-snmp库的编译(vs2015+)

1.获取net-snmp源码 从 net-snmp 官网 选择不同的版本下载,在此我使用的是5.8版本,也可以根据自己的需要下载不同的版本。

2.编译net-snmp静态库netsnmp.lib

下载完成后正常解压,解压完毕后进入到解压后的文件夹中,找到win32文件夹,点击进入。

然后再找到其中的libsnmp文件夹进入,进入后点击这个libsnmp.dsp文件进行vs2015升级,升级完成后会生成对应的.vcxproj文件

双击libsnmp.vcxproj文件进入到项目工程中

由于我的项目需要64位的netsnmp库,所以我还需要增加x64的编译选项(32位库可跳过此步骤),选择如下"配置管理器步骤"。

活动解决方案选择"release",平台选择"新建"

新平台选择"x64",复制设置选择"x86"平台,最后点击确定按钮即可。

选择刚添加的x64平台,项目属性如下设置(可以不用设置),最后点击项目的生成按钮即可

等待生成结果,生成的静态库文件位于下图信息所示位置。

三.程序集成

集成net-snmp库采用静态库集成的方式,我们需要已经生成的netsnmp.lib文件和源码包中include文件夹下的net-snmp文件

最终的snmp集成文件配置如下,include文件夹是net-snmp文件夹(位置上述已明确)和lib文件夹下的netsnmp.lib,这样程序文件的配置就按此结构进行配置。

我的程序名为SNMPDemo(大家可以自己写个demo配置),我之前配置的是绝对路径(相对路径报错)大家可以根据自己的情况进行配置。

四.源码解析

1.踩坑1 包含目录必须包含#include <winsock2.h> #include <ws2tcpip.h> 这两个依赖项,因为snmp是基于socket和UDP协议的,这是

2.踩坑2 初始化snmp结构体调用snmp_open函数前必须调用window SDK的宏SOCK_STARTUP打开socket传输,不然你的snmp_open函数返回永远是空的。

其余的代码注释已经很详细了,源码和动态库连接在以下连接(嫌麻烦的可以直接下载),本文旨在记录,有问题的可以评论或者私信反馈。

#pragma execution_character_set("utf-8")
#include "SNMPDemo.h"
#include <iostream>
#include <net-snmp/net-snmp-config.h>  
#include <net-snmp/output_api.h>
#include <net-snmp/net-snmp-includes.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <QDebug>
#pragma comment(lib, "ws2_32.lib") 

void SNMPDemo::SnmpGet() 
{
	//SNMP对象初始化
	init_snmp("snmp get");
	struct snmp_session sessionToPeer;
	snmp_sess_init(&sessionToPeer);
	sessionToPeer.peername = strdup("192.168.1.100:161");
	sessionToPeer.version = SNMP_VERSION_2c;
	sessionToPeer.community = (u_char*)("public");
	sessionToPeer.community_len = strlen((const char*)sessionToPeer.community);
	sessionToPeer.retries = 3;
	sessionToPeer.timeout = 2000000;//等待时间2s(单位微妙)
	SOCK_STARTUP;
	struct snmp_session* sessionReturnedByLibrary = snmp_open(&sessionToPeer);
	if (sessionReturnedByLibrary == NULL) 
	{
		SOCK_CLEANUP;
		int clib_errno, snmp_errno;
		char* err_string;
		snmp_sess_error(&sessionToPeer, &clib_errno, &snmp_errno, &err_string);

		ui.textEdit->append(QString("初始化SNMP对象失败!失败原因:%1 失败代码:%2_%3").arg(err_string).arg(clib_errno).arg(snmp_errno));
		return;
	}
	else
	{
		ui.textEdit->append(QString("初始化SNMP对象成功!地址:%1 社区名称:%2").arg(QString::fromUtf8(sessionToPeer.peername)).arg(QString::fromUtf8((char*)sessionToPeer.community)));
	}

	//创建SNMP GET请求PDU(Protocol Data Unit)
	struct snmp_pdu* requestGetPdu = snmp_pdu_create(SNMP_MSG_GET);
	if (!requestGetPdu) 
	{
		ui.textEdit->append("初始化SNMP GET请求PDU对象失败!");
		return;
	}

	//初始化OID变量
	oid requestOid[MAX_OID_LEN];           //OID数组(Net-SNMP使用oid类型,即unsigned int数组)
	size_t requestOidLength = MAX_OID_LEN; //OID数组的初始长度

	//解析OID字符串 例子:设备描述Oid:.1.3.6.1.2.1.1.1.0
	if (!snmp_parse_oid(".1.3.6.1.2.1.1.1.0", requestOid, &requestOidLength)) 
	{
		ui.textEdit->append("初始化OID对象失败!");
		snmp_free_pdu(requestGetPdu);
		return;
	}
	//向PDU中添加要查询的OID(NULL值表示请求获取该OID的值)每个OID对应一个变量绑定(Variable Binding)
	snmp_add_null_var(requestGetPdu, requestOid, requestOidLength);

	//发送请求并同步等待响应(同步请求时 创建的GetPdu(requestGetPdu)会自动释放
	struct snmp_pdu* responseGetPdu = NULL; //存储响应PDU的指针
	int snmpStatus = snmp_synch_response
	(
		sessionReturnedByLibrary, //已打开的SNMP会话句柄
		requestGetPdu,            //请求PDU
		&responseGetPdu           //用于接收响应PDU的指针
	);
	//检查SNMP请求状态
	if (snmpStatus == STAT_SUCCESS)//底层通信成功(如收到响应)
	{ 
		 //检查PDU是否包含错误(如权限不足、OID不存在等)
		if (responseGetPdu->errstat == SNMP_ERR_NOERROR)
		{
			//遍历响应中的所有变量绑定(通常一个请求对应一个响应变量)
			struct variable_list *snmpVariables;
			for (snmpVariables = responseGetPdu->variables;
				snmpVariables != NULL;
				snmpVariables = snmpVariables->next_variable)
			{
				//处理不同类型的SNMP值
				if (snmpVariables->type == ASN_OCTET_STR)
				{
					char* response = (char *)malloc(1 + snmpVariables->val_len);
					if (response)//检查内存分配是否成功
					{ 
						memcpy(response, snmpVariables->val.string, snmpVariables->val_len);
						response[snmpVariables->val_len] = '\0';
						ui.textEdit->append(QString("接收到 OCTET_STR 值:%1").arg(response));
					
						free(response);
						response = NULL;
					}
				}
				else if (snmpVariables->type == ASN_INTEGER)
				{
					long intValue = *snmpVariables->val.integer;
					ui.textEdit->append(QString("接收到 INTEGER 值: %1").arg(intValue));
				}
				else if (snmpVariables->type >= ASN_CONTEXT)
				{
					//获取上下文标签号(低7位)
					int contextTag = snmpVariables->type & 0x7F;
					ui.textEdit->append(QString("接收到 ASN_CONTEXT 值: %1").arg(contextTag));
				}
				else 
				{
					ui.textEdit->append(QString("不支持的 SNMP 类型:%1").arg(snmpVariables->type));
				}
			}
		}
		else 
		{
			//PDU包含错误(如社区名错误、OID不可访问)
			ui.textEdit->append(QString("SNMP返回错误:%1").arg(snmp_errstring(responseGetPdu->errstat)));
		}
	}
	else
	{
		switch (snmpStatus) 
		{
		case STAT_TIMEOUT:
			ui.textEdit->append(QString("SNMP返回超时!"));
			break;
		case STAT_ERROR:
			ui.textEdit->append(QString("SNMP连接失败!"));
			break;
		default:
			ui.textEdit->append(QString("未知错误!"));
		}
	}

	if (responseGetPdu)
	{
		snmp_free_pdu(responseGetPdu);
	}
	SOCK_CLEANUP;
}

五.源码下载地址

Windows下的net-snmp64位库,c++(Qt)Demo资源-CSDN文库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值