现在的位置: 首页 > 综合 > 正文

SNMP trap消息为何不能正确发往指定端口162.

2013年10月19日 ⁄ 综合 ⁄ 共 2179字 ⁄ 字号 评论关闭

最近做网络摄像机,有局点要求需要按SNMP协议上报消息,于是从网站http://www.net-snmp.org/下载了一个snmp源码包5.2.6,tar解压,交叉编译:

./configure --build=i686-linux --host=arm-merlin-linux CC=arm-merlin-linux-uclibc-gcc --with-mib-modules="examples/notification" --with-endianness=little LDFLAGS="-static"

(表示在x86的linuxOS上编译板上运行的程序,build是编译机,host是运行机,CC是编译器名,target不需要,因为编译出来的不是工具,加入一个notification的mib库,如何加入mib,看官网上有,最后使用小端静态编译)

如果在PC上用,则./configure --with-mib-modules="examples/notification" 简单的不得了

 

下面的代码演示如何从一个代理进程向管理进程上报trap消息(此处用来发心跳),当然也可以通过配置snmp让它自动上发trap消息,但我们想编程自己灵活控制.

 

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <strings.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/time.h>

#include <time.h>

#include <sys/select.h>

#include <sys/socket.h>

#include <netdb.h>

#include <arpa/inet.h>

 

#include <net-snmp/net-snmp-config.h>

#include <net-snmp/net-snmp-includes.h>

 

int main()

{

netsnmp_session ,session;

static int i=0;

if (i==0)

{

snmp_sess_init(&session);

i=1;

}

 

session.version = SNMP_VERSION_2c;

session.peername = "192.168.1.3";

session.remote_port = 162;

session.community = (unsigned char*)"public";

session.community_len = strlen((char*)session.community);

session.retries = 3;

session.timeout = 2000;

session.sessid = 0;

 

snmp_session *ss = snmp_open(&session);

if (ss==NULL) return -1;

 

netsnmp_pdu *pdu = snmp_pdu_create(SNMP_MSG_TRAP2);

long sysuptime = get_uptime();

char csysuptime[32];

sprintf(csysuptime,"%ld", sysuptime);

oid oid_sysuptime[] = {1,3,6,1,2,1,1,3,0};

int status = snmp_add_var(pdu, oid_sysuptime,OID_LENGTH(oid_sysuptime),'t', csysuptime);

if (status !=0) return -1;//一般不会出错

 

status = snmp_send(ss,pdu);

if (status == 0) return -2; //send要有东西发出去,返回0就不对了

 

snmp_close(ss);

return 0;

}

//以上的变量定义是按Effective C++的第XX条的原则:变量要到了用的时候才定义,个人喜欢这一条,所以坚持用了,除非是一些老的编译器,变量定义必须放在前面,否则我不会先定义一大堆的变量放在那晾着.

 

编译运行,管理进程未收到trap消息(何为管理进程,何为代理进程,看看资料或<tcp/ip详解 卷一就知道了)

抓包一看,发现消息发到161端口去了,上百度搜了一下,发现人家也有同样的问题,无果,最后几番折腾,才在一个SNMP_API.H文件里看到一个结构体stuct snmp_session一行注释:

/**UDP port number of peer (LO LONGER USED - USE peername INSTEAD)*/

u_short remote_port;

原来这个参数不用了,搞不懂为何要用peer_name来替代端口号,却还让remote_port这个字段放在这继续让程序员犯错,不用了为何不注释掉这个字段?让人家编译就能查错总比运行时诡异要好的多吧.

 

修改一下代码:

session.peername = "192.168.1.3:162";//应该是用这个格式

再试一下../sendtrap(make后生成的执行文件) 果然,管理进程正确收到消息了.抓包也可以看到destination port是162了.

 

再把

session.remote_port = 0;,不影响正确性.

抱歉!评论已关闭.