异步manager实现
一, 基本步骤
初始化部分
1,init_snmp初始化snmp
2,snmp_parse_oid根据mib分析parse oid
循环执行3-7,直到所有pdu都发出去
3,snmp_sess_init初始化session,然后用一些赋值语句设置session
4,设置session中的回调函数(callback),这个函数负责处理返回的信息
5,snmp_open打开session
6,snmp_pdu_create创建pdu
7,snmp_send发送包
循环执行8-10,直到没有active hosts
8,snmp_select_info设置多路复用的几个信息
9,select多路复用
10,snmp_read接受所有返回信息,具体处理交给callback
11,回调函数(callback),具体处理返回信息,参数是固定的,参数是:
int operation, struct snmp_session *sp, int reqid,struct snmp_pdu *pdu, void *magic
根据这些可以处理返回信息
二, 代码全注释
参照
更改了一些代码,read_objid改为snmp_parse_oid,更改了host中的name
删除了同步代码,和windows相关部分
#include
#include
/*
* a list of hosts to query
*/
Host结构
struct host {
const char *name;
const char *community;
} hosts[] = {
{ "192.168.213.116", "public" },
{ "192.168.213.64", "public" },
{ "192.168.213.116", "public" },
{ "192.168.213.64", "public" },
{ NULL }
};
/* a list of variables to query for*/
Oid结构
struct oid {
const char *Name;
oid Oid[MAX_OID_LEN];
int OidLen;
} oids[] = {
{ "system.sysDescr.0" },
{ "interfaces.ifNumber.1" },
{ "interfaces.ifNumber.0" },
{ NULL }
};
/*
* initialize
*/
初始化函数
void initialize (void)
{
struct oid *op = oids;
/* Win32: init winsock */
SOCK_STARTUP;
/* initialize library */
初始化snmp库
init_snmp("asynchapp");
/* parse the oids */
根据mibs来parse oids
while (op->Name) {
op->OidLen = sizeof(op->Oid)/sizeof(op->Oid[0]);
if (!snmp_parse_oid (op->Name, op->Oid, &op->OidLen)) {
snmp_perror("read_objid");
exit(1);
}
op++;指向oids数组的下一项
}
}
/* simple printing of returned data*/
打印返回结果,这部分不是很重要,编写处理函数时候可以参考
int print_result (int status, struct snmp_session *sp, struct snmp_pdu *pdu)
{
char buf[1024];
struct variable_list *vp;
int ix;
struct timeval now;
struct timezone tz;
struct tm *tm;
gettimeofday(&now, &tz);
tm = localtime(&now.tv_sec);
fprintf(stdout, "%.2d:%.2d:%.2d.%.6d ", tm->tm_hour, tm->tm_min, tm->tm_sec,
now.tv_usec);
switch (status) {
case STAT_SUCCESS:
vp = pdu->variables;
if (pdu->errstat == SNMP_ERR_NOERROR) {
while (vp) {
snprint_variable(buf, sizeof(buf), vp->name, vp->name_length, vp);
fprintf(stdout, "%s: %s\n", sp->peername, buf);
vp = vp->next_variable;
}
}
else {
for (ix = 1; vp && ix != pdu->errindex; vp = vp->next_variable, ix++)
;
if (vp) snprint_objid(buf, sizeof(buf), vp->name, vp->name_length);
else strcpy(buf, "(none)");
fprintf(stdout, "%s: %s: %s\n",
sp->peername, buf, snmp_errstring(pdu->errstat));
}
return 1;
case STAT_TIMEOUT:
fprintf(stdout, "%s: Timeout\n", sp->peername);
return 0;
case STAT_ERROR:
snmp_perror(sp->peername);
return 0;
}
return 0;
}
/*
* poll all hosts in parallel
*/
struct session {
struct snmp_session *sess; /* SNMP session data */
struct oid *current_oid; /* How far in our poll are we */
} sessions[sizeof(hosts)/sizeof(hosts[0])];数量跟host一样多
active_hosts在asynch_response中减少,在asynchronous中增加
int active_hosts; /* hosts that we have not completed */
/*
* response handler
*/
int asynch_response(int operation, struct snmp_session *sp, int reqid,
struct snmp_pdu *pdu, void *magic)
{
struct session *host = (struct session *)magic;
struct snmp_pdu *req;
if (operation == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
if (print_result(STAT_SUCCESS, host->sess, pdu)) {
每个host对应了3个oid,对每个都要发送包
asynchronous发送第一个包,这里对其他的oid发送包
host->current_oid++; /* send next GET (if any) */
下面的程序跟asynchronous中处理相同
if (host->current_oid->Name) {
req = snmp_pdu_create(SNMP_MSG_GET);
snmp_add_null_var(req, host->current_oid->Oid, host->current_oid->OidLen);
if (snmp_send(host->sess, req))
return 1;
else {
snmp_perror("snmp_send");
snmp_free_pdu(req);
}
}
}
}
else
print_result(STAT_TIMEOUT, host->sess, pdu);
/* something went wrong (or end of variables)
* this host not active any more
*/
active_hosts--;处理完后,少了一个active host
return 1;
}
void asynchronous(void)
{
struct session *hs;
struct host *hp;
/* startup all hosts */
for (hs = sessions, hp = hosts; hp->name; hs++, hp++) {
struct snmp_pdu *req;
struct snmp_session sess;
snmp_sess_init(&sess); 初始化session /* initialize session */
设置session的各变量
sess.version = SNMP_VERSION_2c;
sess.peername = strdup(hp->name);
sess.community = strdup(hp->community);
sess.community_len = strlen(sess.community);
sess.callback = asynch_response;设置回调函数 /* default callback */
sess.callback_magic = hs;回调函数的magic,传入打开的session
初始化和打开后返回的session不同
if (!(hs->sess = snmp_open(&sess))) {
snmp_perror("snmp_open");
continue;
}
设置oid
hs->current_oid = oids;
创建pdu
req = snmp_pdu_create(SNMP_MSG_GET); /* send the first GET */
snmp_add_null_var(req, hs->current_oid->Oid, hs->current_oid->OidLen);
用异步方式发送包,不处理,等后面专门处理
if (snmp_send(hs->sess, req))
active_hosts++;增加一个活跃的host
else {
snmp_perror("snmp_send");
snmp_free_pdu(req);
}
}
/* loop while any active hosts */
while (active_hosts) {只要有活跃的host就一直处理
int fds = 0, block = 1;
fd_set fdset;
struct timeval timeout;
FD_ZERO(&fdset);把fd_set清零
Select具体应用请参考《unix网络编程》,或者internet高级编程讲义
设置select需要的信息
snmp_select_info(&fds, &fdset, &timeout, &block);
多路复用,直接这么用就行了
fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout);
if (fds name; hs++, hp++) {
if (hs->sess) snmp_close(hs->sess);
}
}
/*****************************************************************************/
int main (int argc, char **argv)
{
initialize();
printf("---------- asynchronous -----------\n");
asynchronous();
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/95634/showart_2010975.html