声明 :本文的大部分资源参考自文章,编译snmp++的方法我也是在这里学习的,结合自己的需求,做了snmp++和Agent++的混合编译。需要了解更多的详情可以点击链接去看原文,我总结了自己的编译过程,并写下此文作为一个回国笔记,希望能帮助到同样有此需求的人。
文章目录
- 一 前期准备
- 二 源码准备
- 三 配置编译环境
- (一).工程文件建立
- (二).将snmp++和Agent++ 源代码复制进来
- (三).修改工程文件的一些内容
- 四 漫长的修正bug之路
- 报错1,“netdb.h:No such file or directory”
- 报错2,“‘in6_addr’was not declared in this scope”
- 报错3,“openssl/des.h:No such file or directory”
- 报错4,“des.h:No such file or directory”
- 报错5,“undefined reference to ‘_imp_htonl’”
- 报错6,“undefined reference to ‘des_key_sched’”
- 五 编译结果
- 六 注意事项
- 七 运用编译的库
- 五 测试代码
- 链接
一 前期准备
操作系统:win11
qt版本:5.8,QtCreator版本为4.2.1
编译器版本:5.8.0_MinGW_32_bit
二 源码准备
准备snmp++和des和 agent++的源码。snmp++就是实现snmp功能的主要代码,des是用来加密算法,agent++写代理的时候用得着。建议和snmp++一起编译了。
下载地址官网
下载文件然后解压。绿色框的地方点开是对应的开发文档。右下角有一个agent++的帮助文档,建议需要开发的朋友一并下载了。
三 配置编译环境
(一).工程文件建立
1.新建一个Qt工程文件
1.选择创建c++Library
2.命名工程,这里命名为snmp_dev
3.创建共享库,Shared Library
4.选择编译器为mingw。
(二).将snmp++和Agent++ 源代码复制进来
1.打开刚才解压后的snmp++和agent++文件夹,分别将下属三部分内容复制
2.先看看snmp++的include中的内容。可见,snmp__pp文件夹,该文件夹中包含了绝大部分的头文件,将该文件夹(snmp_pp)复制,粘贴至刚创建的snmp_dev工程目录下,Agent++目录的操作也是一样的。
3.打开snmp++的src文件,可以看见一堆的cpp文件,将该部分所有的cpp文件,复制到snmp_dev工程目录下,Agent++的文件操作也是一样的
4.此使,snmp_dev工程文件下,可以看见如下的部分内容,有一部分将在后续过程中,再复制进来
![这个已经是我编译过的文件了,所以会有些多的东西](https://i-blog.csdnimg.cn/direct/32c9ec964d234ed684d49865d9662c75.png](https://i-blog.csdnimg.cn/direct/ef94e1e89cbe4fbc9ed930fe41eb3445.png)
5.将所有.h和.cpp文件导入工程中
6.到这一步,导入就暂时告一段落。
(三).修改工程文件的一些内容
1.刚创建的snmp_dev工程中,同时生成的有snmp_dev.h与snmp_dev.cpp。下面需要修改这两个文件内容。
2.删除snmp_dev.cpp。
3.修改snmp_dev.h头文件,删除部分内容,添加一个include,修改至如图,务必要修改。
4.至此,就可以点击一下左下角哪个锤子按钮,开始尝试编译了,当然,会有一堆报错,我挨个分析。
四 漫长的修正bug之路
报错1,“netdb.h:No such file or directory”
1.报错:首先出现的报错如图,对应的libsnmp.cpp文件如图所示
2.分析:从报错位置来看,百度可知,这部分报错的可能原因,猜测是因为该部分头文件再windows中并不存在,是linux中的内容,不管是不是这个原因,可以确定的是,这几个头文件压根就不存在
3.解决:头文件不存在,那就不加载就行了,因此,做如下修改:
报错2,“‘in6_addr’was not declared in this scope”
1.报错:接着编译,锤子,然后出现新的问题,这次出现再address.cpp中。
2.分析:分析编译出错的部分的内容,可以猜测,这部分内容是与ipv6相关,关键词搜索宣称的不存在的内容,没找到定义的位置,因此想到,能不能直接不要这部分,因为其实现在我所接触的大部分时候,还用不着IPV6,因此干脆不要了。那如何能让他不编译,看见上面写着ifdef SNMP_PP_IPv6,意思是,如果定义了SNMP_PP_IPv6,就执行下面一部分内容,那直接不定义SNMP_PP_IPv6,不就行了?于是,全局搜索define SNMP_PP_IPv6,果然存在。
3.解决:将上图中的,红框内的内容,注释掉即可,问题解决
报错3,“openssl/des.h:No such file or directory”
1.报错:这次出问题的是auth_priv.cpp,分析其中内容
2.分析:由报错的内容分析,可以看出来,这一部分是用来加密用的,这个情况很明显,就是却一个des.h头文件,这个头文件很眼熟,没错,在刚刚下载的两个源代码中,解压了snmp++,而另一个libdes一直还没用上,里面就有一个des.h,那是不是复制过来就行?这并不能解决问题,因为可以看见,即便des.h找到了,后面两个人就不存在,因此,问题的根本在于,是否需要使用openssl,实际上是可以不用这个的。
3.解决:因此,根据ifdef _USE_OPENSSL可知,搜索define _USE_OPENSSL。如下图,注释掉红框内的内容即可。
报错4,“des.h:No such file or directory”
1.报错:上一步将openssl给禁用了,新的报错出现了。
2.分析:很明显,就是在将openssl禁用的情况下,这个snmp++有备选方案,备选方案,没错,就是使用libdes,即下载的两个文件,一个snmp++,一个libdes,刚仅仅使用了snmp++,这会将发挥libdes的作用了,在解压libdes后发现,里面有des.h文件。
3.解决:libdes文件夹下,有多个头文件和cpp文件,不晓得需不需要将别的也复制过来,但是,既然报错是des.h文件,那就先解决眼下的问题。复制过来后,编译,这个问题解决了。
报错5,“undefined reference to ‘_imp_htonl’”
报错:这只是第一条,出现的不仅仅这条报错。
2.分析:上网百度可以发现,缺失的内容都是一个叫ws2_32的库文件,这是提供了对部分网络相关API的支持的,这个库系统中会自带,因此,只需要引入即可。
3.解决:在.pro文件中添加 LIBS += -lws2_32,问题解决。
报错6,“undefined reference to ‘des_key_sched’”
1.报错:又出现新的报错。
2.分析:undefined,意思肯定是缺少了一些库文件或者什么内容的调用。再观察到缺少的东西的名字,里面有一个des的字眼,猜测估计就是缺少了libdes文件夹下的内容
3.解决:不知道缺的是哪个,一不做二不休,把libdes下的所有.h和.c都复制过来,编译,问题果然解决。
五 编译结果
1.查看编译生成的内容
图中点选即生成的内容,.a和.dll库文件,即开发所需的.a文件,和运行过程中需要的.dll文件。
六 注意事项
1.一定要搞清楚头文件和cpp文件等存放的位置,报错各个头文件的拓扑关系,这在后续的库文件的使用中,尤其重要。
2.编译过程中,缺什么别慌,冷静分析,看能不能找不到,同时也得注意看代码,分析是否可以跳过该部分内容。
3.注意关注点,生成库文件的工程文件,比如我所用的例子中的,snmp_dev.h和snmp_dev.cpp文件,一定记得删除cpp文件,然后在.h文件中,将原来的内容全清空了,主要指的是原有的class等内容,只需要引入#include snmp/snmp_pp.h即可。如原有的class等内容不清空,编译中虽然不报错,但是编译出的.a文件就是空文件,无法使用。
4.编译结果的.a和.dll文件,区别在于.a是程序编译生成所需,.dll是程序运行所需的。
七 运用编译的库
1搞清楚我们有什么库文件以及放在哪
动态库文件。有两个,一个是snmp_dev.a,一个是snmp_dev.dll,以及相应的头文件。我们将这两个库文件放在同一个文件夹下,比如创建一个名为lib的文件夹。将该文件夹放置在需调用snmp功能的工程文件的目录下。同时,创建一个名为include的文件夹,将头文件放进该文件夹下,将include文件夹也放置在该工程目录下。snmp_dev.a是为了编译使用,snmp_dev.dll是为了程序运行使用,没有.dll库文件,exe文件无法运行。因此在发布时,需要将snmp_dev.dll文件复制到与exe同个目录下。
include的文件夹下的文件
lib文件夹下面的文件
2 库文件及头文件的导入
3.选择 外部库
4.动态库的导入如下选择,勾选动态
五 测试代码
服务器的代码
#include <QCoreApplication>
#include<snmp_dev.h>
#include<snmp_pp/snmp_pp.h>
#include<snmp_pp/oid.h>
#include <winsock2.h>
using namespace std;
using namespace Snmp_pp;
//#pragma comment(lib, "ws2_32.lib")
#define SYSDESCR "1.3.6.1.2.1.1.1.0" //ObjectID for system descriptor
#define SYSOBJECTID "1.3.6.1.2.1.1.2.0" //ObjectID for system object ID
#define SYSCONTACT "1.3.6.1.2.1.1.4.0" //ObjectID for system contact
#define coldStart "1.3.6.1.6.3.1.1.5.1"
#define ZYX1 "1.3.6.1.2.1.1.1.1"
#define ZYX2 "1.3.6.1.2.1.1.1.2"
#define ZYX3 "1.3.6.1.2.1.1.1.101"
using namespace std;
using namespace Snmp_pp;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Snmp::socket_startup(); //初始化socket子系统
int status;
Vb vb[3];
Pdu pdu;
vb[0].set_oid(SYSDESCR);
vb[1].set_oid(ZYX1);
vb[2].set_oid(ZYX3);
pdu.set_vblist(vb,3);
CTarget ctarget((IpAddress) "127.0.0.1"); //被管代理的ip
Snmp snmp(status);
if((status=snmp.get(pdu, ctarget))!=SNMP_CLASS_SUCCESS)
{
cout<<snmp.error_msg(status);
}
else
{
pdu.get_vblist(vb,3);
for(int i=0;i<3;i++)
{
cout<<"oid:"<<vb[i].get_printable_oid()<<" "<<"value:"<<vb[i].get_printable_value()<<endl;
}
}
return a.exec();
}
代理的代码
#include <QCoreApplication>
#include "agent_dev.h"
#include "agent_dev_global.h"
#include<snmp_pp/snmp_pp.h>
#include<agent_pp/agent++.h>
#include<agent_pp/mib.h>
#include<agent_pp/mib_entry.h>
#include<agent_pp/request.h>
#include<QDebug>
#include<agent_pp/snmp_group.h>
#include<agent_pp/system_group.h>
#include <agent_pp/snmp_target_mib.h>
#include <agent_pp/snmp_notification_mib.h>
#include"qagent.h"
using namespace std;
using namespace Snmp_pp;
using namespace Agentpp;
#define SYSDESCR "1.3.6.1.2.1.1.1.0" //ObjectID for system descriptor
#define SYSOBJECTID "1.3.6.1.2.1.1.2.0" //ObjectID for system object ID
#define SYSCONTACT "1.3.6.1.2.1.1.4.0" //ObjectID for system contact
#define coldStart "1.3.6.1.6.3.1.1.5.1"
#define ZYX1 "1.3.6.1.2.1.1.1"
#define ZYX2 "1.3.6.1.2.1.1.2"
#define ZYX3 "1.3.6.1.2.1.1.101"
bool run = true;
static void sig(int signo)
{
if ((signo == SIGTERM) || (signo == SIGINT) ||(signo == SIGSEGV))
{
printf ("\n");
switch (signo)
{
case SIGSEGV:
{
qDebug()<<"Segmentation fault, aborting.";
exit(1);
}
case SIGTERM:
case SIGINT:
{
if (run)
{
qDebug()<<"User abort";
run = false;
}
}
}
}
}
void init_signals()
{
signal (SIGTERM, sig);
signal (SIGINT, sig);
signal (SIGSEGV, sig);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Snmp::socket_startup();
int status;
unsigned short port = 161; //161为监听端口 162为Trap端口
UdpAddress address("127.0.0.1");
address.set_port(port);
Snmpx snmp(status,address);
if( SNMP_CLASS_SUCCESS == status)
{
Mib mib;
//将oid 和对应的value放入这个Mib里面,等请求到到来的时候 代理会在这个Mib里面查询相应的信息来处理
mib.add(new snmpGroup());
mib.add(new snmp_target_mib());
mib.add(new snmp_notification_mib());
mib.add(new MibLeaf("1.3.6.1.2.1.1.1.0", READONLY, new OctetStr("SYSDESCR")));
mib.add(new MibLeaf("1.3.6.1.2.1.1.1.1", READONLY, new OctetStr("zyx1")));
mib.add(new MibLeaf("1.3.6.1.2.1.1.1.2", READONLY, new OctetStr("zyx2")));
mib.add(new MibLeaf("1.3.6.1.2.1.1.1.101", READWRITE, new OctetStr("zyx3")));
//创建RequestList
RequestList* reqList = new RequestList(&mib);
mib.set_request_list(reqList);
init_signals();
reqList->set_snmp(&snmp);
mib.init(); //mib 初始化
//监听循环 此处循环何时退出可根据实际情况来做修改
Request* req;
while (run)
{
req = reqList->receive(5);
if (req)
{
mib.process_request(req);//对请求进行处理,请求包括get,getNext,getBulk,walk,set。
}
else
{
mib.cleanup();
}
}
delete reqList;
Snmp::socket_cleanup();
}
else
{
qDebug()<<"snmp port init failed!";
}
return a.exec();
}
我们先运行代理,开始监听请求,如下:
然后我们运行 服务器,发起get请求。
get之后获得得数据都打印了出来,oid和value对应。get时的iod一定是代理里面的Mib添加了的,存在的oid.
链接
接下来,我将对snmp里面的get,getNext,getBulk,set,trap,inform这六种操作进行一一的讲解。
1.snm++操作之get
2.snmp++操作之getNext
3.snmp++操作之getBulk
4.snmp++操作之walk
5.snmp++操作之set
6.snmp++操作之trap
7.snmp++操作之阻塞式inform
8.snm++操作之异步inform