使用 C/C++ 进行 SNMP 开发,网上比较流行的主要是用 net-snmp 和 snmp++ 。在 sourceforge 上以 Qt 和 snmp 为关键词进行搜索,搜到的项目 net-snmp 相关的占了多数,推测,net-snmp 的使用人数可能更多一点。遂决定采用 net-snmp。

仍然是从 sourceforge 开始,随便找了一个规模不大的项目,开始对 net-snmp 进行熟悉。

1. 尝试代码编译

从项目把代码拉过来: git clone https://git.code.sf.net/p/qt-snmp/code qt-snmp-code

文件里没有 project 文件,使用 qt -project 生成 source.pro,qmake,make。

遇到没有 net-snmp-config.h 头文件的问题,很明显,是因为 net-snmp 库没有安装。

2. 安装 libnetsnmp

首先,因为这个代码库看起来比较早,所以选择了一个比较早期的 net-snmp 版本(2011)。snmp 已经是非常成熟的协议,所以,并不担心比较早的版本协议实现不完整。

从 sourceforge 下载代码包 net-snmp-5.4.4.tar.gz,并解压,进入代码根目录。

因为 net-snmp 的部分实现严重依赖 perl,所以,需要先安装 perl 的开发包:

然后进行 configure , make , make install.

另外,net-snmp 还依赖 openssl。在这里花了比较长的时间。因为我的交叉编译器只有 openssl 头文件,并没有库文件,而且我编译 net-snmp 又是用的静态库,所以,链接的时候老是提示没有一些加密函数。下面是我重新编译 openssl 的 config 配置(用从 ubuntu 下 的 openssl098_0.9.8o.orig.tar.gz):

CC=arm-linux-gcc ./config no-asm --prefix=/tmp/openssl

为 arm 编译 net-snmp 库使用的 configure 选项:

 ../configure --host=arm-linux --target=arm-linux --build=i686-linux --disable-shared --disable-scripts -enable-mini-agent --disable-ipv6 --disable-manuals --disable-ucd-snmp-compatibility --enable-as-needed --with-endianness=little --prefix=/tmp/snmp/

3. 继续编译 demo 的代码

因为已经安装了 libnetsnmp,而且代码要用到这个包,所以需要修改 project 文件,添加:

LIBS +=-lnetsnmp

make,成功。

暂时没有测试的环境,不知道程序是否有效,暂时先阅读一下代码。

4. 阅读项目代码

读完代码发现,真的只是写了一个最基本的 demo,界面倒是看起来做了一堆。甚至怀疑他这个最基本功能有没有实现,暂时没法测试,学习一下他的过程。

最主要业务代码,是在 snmpGet() 函数里,全文如下:

void MainWindow::SnmpGet() {
init_snmp("snmp get");
struct snmp_session sessionToPeer;
snmp_sess_init(&sessionToPeer); sessionToPeer.peername = strdup(agentDeviceAddressLineEdit->text().toStdString().c_str());
/*memory allocated by strdup() will be freed by calling snmp_close() */
if(snmpVersion1RadioButton->isChecked()) {/* snmp version 1 is obsolete, do nothing about it. */
}
if(snmpVersion2RadioButton->isChecked()) {/* only version 2 community is implemented here */
sessionToPeer.version = SNMP_VERSION_2c;
sessionToPeer.community = (u_char*) (strdup(communityLineEdit->text().toStdString().c_str()));
sessionToPeer.community_len = strlen((const char*) sessionToPeer.community);
}
if(snmpVersion3RadioButton->isChecked()) { //TODO: implement SNMP version 3 options. more item may be needed to add to combo box. }
sessionToPeer.retries = retriesSpinBox->value();
sessionToPeer.timeout = timeoutSpinBox->value();
SOCK_STARTUP;
struct snmp_session* sessionReturnedByLibrary = snmp_open(&sessionToPeer);
if(sessionReturnedByLibrary == NULL) {
#ifdef QT_DEBUG
snmp_sess_perror((const char*) "No Ack!", sessionReturnedByLibrary);
#endif //QT_DEBUG
SOCK_CLEANUP;
return;
}
struct snmp_pdu* requestPdu = snmp_pdu_create(SNMP_MSG_GET);
oid requestOid[MAX_OID_LEN];
size_t requestOidLength = MAX_OID_LEN;
snmp_parse_oid(".1.3.6.1.2.1.1.1.0", requestOid, &requestOidLength);
snmp_add_null_var(requestPdu, requestOid, requestOidLength);
struct snmp_pdu* responsePdu = NULL;
int snmpStatus = snmp_synch_response(sessionReturnedByLibrary, requestPdu, &responsePdu);
if(snmpStatus == STAT_SUCCESS and responsePdu->errstat == SNMP_ERR_NOERROR) {
/* SUCCESS: Print the result variables */
struct variable_list *snmpVariables;
#ifdef QT_DEBUG
for(snmpVariables = responsePdu->variables; snmpVariables; snmpVariables = snmpVariables->next_variable) {
print_variable(snmpVariables->name, snmpVariables->name_length, snmpVariables);
}
#endif //QT_DEBUG
/* retrieve response that we're interested. */
#ifdef QT_DEBUG
int count = ;
#endif //QT_DEBUG
for(snmpVariables = responsePdu->variables; snmpVariables != NULL; snmpVariables = snmpVariables->next_variable) {
if(snmpVariables->type == ASN_OCTET_STR) {
char* response = (char *) malloc( + snmpVariables->val_len);
memcpy(response, snmpVariables->val.string, snmpVariables->val_len);
response[snmpVariables->val_len] = '\0';
#ifdef QT_DEBUG
printf("value #%d is a string: %s\n", count++, response);
#endif //QT_DEBUG
resultTextEdit->setText(QString(response));
free(response);
} else {
#ifdef QT_DEBUG
printf("value #%d is NOT a string! Ack!\n", count++);
#endif //QT_DEBUG
}
}
} else {
/* FAILURE: print what goes wrong! */
#ifdef QT_DEBUG
if(snmpStatus == STAT_SUCCESS) {
fprintf(stderr, "Error in packet\nReason: %s\n", snmp_errstring(responsePdu->errstat));
} else if(snmpStatus == STAT_TIMEOUT) {
fprintf(stderr, "Timeout: No response from %s.\n", sessionToPeer.peername);
} else {
snmp_sess_perror("snmp get", sessionReturnedByLibrary);
}
#endif //QT_DEBUG
} /*
* Clean up:
* 1) free the response.
* 2) close the session.
*/
if(responsePdu) {
snmp_free_pdu(responsePdu);
}
snmp_close(sessionReturnedByLibrary); SOCK_CLEANUP;
}

 大致步骤:

1)  对 snmp 协议栈进行初始化,init_snmp();

2) 新建 snmp 会话,对 session 进行初始化, 并对 session 进行基本的设置,比如 session 使用的协议、session 的重试次数以及等待时间等;

3) 使用 snmp_create_pdu( MSG_TYPE) 来组装 request_pdu。查看这个版本的协议,支持的 pdu 类型有:

    /*
* PDU types in SNMPv1, SNMPsec, SNMPv2p, SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3
*/
#define SNMP_MSG_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x0) /* a0=160 */
#define SNMP_MSG_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x1) /* a1=161 */
#define SNMP_MSG_RESPONSE (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x2) /* a2=162 */
#define SNMP_MSG_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x3) /* a3=163 */ /*
* PDU types in SNMPv1 and SNMPsec
*/
#define SNMP_MSG_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x4) /* a4=164 */ / * PDU types in SNMPv2p, SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 */
#define SNMP_MSG_GETBULK (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x5) /* a5=165 */
#define SNMP_MSG_INFORM (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x6) /* a6=166 */
#define SNMP_MSG_TRAP2 (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x7) /* a7=167 */ /*
* PDU types in SNMPv2u, SNMPv2*, and SNMPv3
*/
#define SNMP_MSG_REPORT (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x8) /* a8=168 */

为 request_pdu 指定 oid(这里指定固定的 oid,mib 文件并没有使用)。

4) 使用 nmp_synch_response(sessionReturnedByLibrary, requestPdu, &responsePdu) 来出发请求,并获取 resopose_pdu.

5) 当正确的获取 response_pdu 之后,在一个 for 循环中历遍 response_pdu 中的 netsnmp_variable_list,将所有 variables 的 value 都按照字符串打印出来。

6) 到所有的最后,关闭 session,删除 pdu。

以上,完成了一个基本的 snmp_get 请求。

Qt 使用 net-snmp 包的过程记录的更多相关文章

  1. openWRT自学---自己编译的第一个 backfire10.03 版本的过程记录 --- 实际是由于下载了错误的backfire源码包导致的

    基于 backfire10.03(从http://downloads.openwrt.org/backfire/10.03/ 中下砸的源码包backfire_10.03_source.tar.bz2: ...

  2. qt之fillder抓包(QT网络版有一些具体的坑)

    最近项目中使用到了Qt的网络库,在用的过程中也发现了不少坑和问题,本文仅仅作为记录,方便日后查阅.    因为我们整个客户端的gui都是使用qt来完成的,心想qt既然有网络库,而且真心觉着qt封装的控 ...

  3. qt之fiddler抓包

    最近项目中使用到了Qt的网络库,在用的过程中也发现了不少坑和问题,本文仅仅作为记录,方便日后查阅.    因为我们整个客户端的gui都是使用qt来完成的,心想qt既然有网络库,而且真心觉着qt封装的控 ...

  4. CentOS 5.5 下安装Countly Web Server过程记录

    CentOS 5.5 下安装Countly Web Server过程记录 1. 系统更新与中文语言包安装 2. 基本环境配置: 2.1. NodeJS安装 依赖项安装 yum -y install g ...

  5. 【转】android 最新 NDK r8 在window下开发环境搭建 安装配置与使用 详细图文讲解,完整实际配置过程记录(原创)

    原文网址:http://www.cnblogs.com/zdz8207/archive/2012/11/27/android-ndk-install.html android 最新 NDK r8 在w ...

  6. 升级到 ExtJS 5的过程记录

    升级到 ExtJS 5的过程记录   最近为公司的一个项目创建了一个 ExtJS 5 的分支,顺便记录一下升级到 ExtJS 5 所遇到的问题以及填掉的坑.由于 Sencha Cmd 的 sencha ...

  7. openWRT自学---自己编译的第一个 backfire10.03 版本的过程记录(转)

    基于 backfire10.03(从http://downloads.openwrt.org/backfire/10.03/ 中下砸的源码包backfire_10.03_source.tar.bz2: ...

  8. 菜鸟如何使用hanlp做分词的过程记录

    菜鸟如何使用hanlp做分词的过程记录 最近在学习hanlp的内容,准备在节后看看有没有时间整理一波hanlp分享下,应该还是会像之前分享DKHadoop一样的方式吧.把整个学习的过程中截图在配文字的 ...

  9. 将React Native 集成进现有OC项目中(过程记录) 、jsCodeLocation 生成方式总结

    将RN集成到现有OC项目应该是最常见的,特别是已经有OC项目的,不太可能会去专门搞个纯RN的项目.又因为RN不同版本,引用的依赖可能不尽相同,所以特别说明下,本文参考的文档是React Native ...

随机推荐

  1. resin 4.0.xx 版破解方法

    how to crack resin 4.0.2x resin 4.0.3x. 工具:jd http://jd.benow.ca/ 利用jd打开resin 4.0.xx目录下的lib/pro.jar ...

  2. JKS和PFX文件相互转换方法

    JKS(JavaKeysotre)格式和PFX(PKCS12)格式,是最常见的SSL证书格式文件,可以包含完整的证书密钥对,证书链和信任证书信息.PFX常用于Windows IIS服务器,JKS常用语 ...

  3. TextKit简单示例

    TextKit简单示例 效果 源码 https://github.com/YouXianMing/Animations // // TextKitLoadImageController.m // An ...

  4. [UI] 精美UI界面欣赏[13]

    精美UI界面欣赏

  5. ios成长之每日一遍(day 1)

    Hello world开始. 这里不讨论如何创建项目导入项目.由于趁上班时间打酱油所以也不谈细节, 只谈具体项目的实现与关键流程的解析, 只供本人实际程况使用.不喜请移驾. 首先来谈谈 AppDele ...

  6. 一分钟了解:String & StringBuilder & StringBuffer

    这三个都是字符串对象,本篇就来分析下它们的使用途径,力求简单明了. 一.String String 长度是不可变的,如果你要改变string对象的字符或者是拼接字符的话,系统就会新建一个string, ...

  7. PHP Curl transfer closed with outstanding read data remaining

    php transfer closed with outstanding read data remaining php curl CURLOPT_HTTPHEADER php curl 报错 tra ...

  8. RSA加密解密及RSA签名和验证及证书

    RSA加密解密及RSA签名和验证及证书 公钥是给别人的 发送密文使用公钥加密 验证签名使用公钥验证 私钥是自己保留的 接受密文使用私钥解密 发送签名使用私钥签名 上述过程逆转是不行的,比如使用私钥加密 ...

  9. 试用ArcGIS Server 10.1 X64 for windows

    ArcGIS 10.1 发布已经很久了,其Server只支持x64,为此我还专门下载安装了windows Server 2003 x64,进行安装测试. 我测试了集群功能,比起10.0 ,没有使用域控 ...

  10. fortran中提取字符串中可见字符的索引

    fortran中常常需要提取字符串中可见字符的索引,下面是个小例子: !============================================================= su ...