windows下使用net-snmp實現agent擴展(一)

項目上需要用snmp來做告警監控管理,達到對系統的運行狀態的監測。這幾天研究了一下,發現網上資料比較少,大多數抄來抄去,能夠正確運行的更少。所以,總結了一下,把相關的代碼放上來,希望能夠幫助同樣遇到困惑的朋友。 havenzhao http://vcsky.net

項目名稱爲DCS系統,採用VS2010開發,DCS作爲被監測的對象,因此需要實現snmp的Agent擴展。最開始的方法,採用了WinSnmp,發現步驟很繁瑣,需要編寫dll,需要手動修改註冊表,需要安裝snmp協議服務,可行性和意義都不大。又研究了開源軟件net-snmp,snmp++,agent++。網上說net-snmp主要適用於Linux平臺,在這幾天的開發中,它完全能夠勝任Windows平臺,只是網上的資料偏少而已。

DCS就是使用net-snmp(版本是5.7.1),實現了Windows平臺下的Agent端,實現了get、set、trap命令。

接下來的工作,我們這樣展開:

1、首先要得到四個lib庫以及一個dll文件:netsnmp.lib netsnmpagent.lib netsnmpmibs.lib netsnmptrapd.lib,netsnmp.dll。在下載了net-snmp的源碼後,編譯,需要閱讀源碼下的“README.win32”文件,工程默認的是VC6.0的,但由於要裝SDK之類的,我直接轉化爲VS2010的了,實際上,還可以轉爲VS2003、VS2005、VS2008,看你手頭上用的哪個版本的編譯器了。只編譯win32dll.dsw工程就可以得到想要的東西了。

2、下載net-snmp的5.4版msi文件安裝,默認路徑C:\usr安裝,安裝過程中選擇開發支持。沒有找到5.7的,隨便下個5.4的,安裝上就行,但要主要選用默認的安裝路徑(更改安裝路徑,不知道可不可行,沒有嘗試),一路默認即可。安裝的目的在於我們要配置後綴名爲conf的文件,沒有這個配置選項,將不能使用net-snmp的服務,我懷疑這個文件在源碼中有個對應關係,不然怎麼知道配置文件在路徑C:\usr\etc\snmp下呢?如果只實現trap命令,這步可以省略。

3、建立C++的控制檯工程,一個空的工程就可以。設置工程的包含頭文件和lib文件。這裏需要注意的一點是:include頭文件,我把net-snmp5.7.1下的頭文件都包含過來了,lib庫文件,就是上面4個lib庫,別忘了設置連接器:在項目屬性的--連接器--輸入--"附加依賴項":添加netsnmp.lib netsnmpagent.lib netsnmpmibs.lib netsnmptrapd.lib wsock32.lib; 如果環境變量沒有起作用,netsnmp.dll與exe文件放在同一文件夾下就可以了。注意:wsock32.lib是其它lib庫裏用到的,缺少它會報錯。

4、工程建立完了,配置好了,那就寫代碼吧!新建3個文件,一個入口函數文件,一個mib庫的實現文件,一個頭文件。我們先拿網上的例子試一下,參照這篇文章;http://hi.baidu.com/haven2002/item/d2d0bac02eed32bd0d0a7b9d

example-demon.c

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <signal.h>

#include "nstAgentSubagentObject.h"

static int keep_running;

RETSIGTYPE
stop_server(int a) {
          keep_running = 0;
}

int main (int argc, char **argv) {
        //int agentx_subagent=1; /* change this if you want to be a SNMP master agent */
        int agentx_subagent=0;
        int background = 0; /* change this if you want to run in the background */
        int syslog = 0; /* change this if you want to use syslog */

        /* print log errors to syslog or stderr */
        if (syslog)
         ;
          //snmp_enable_calllog();
        else
          snmp_enable_stderrlog();

        /* we're an agentx subagent? */
        if (agentx_subagent) {
          /* make us a agentx client. */
          netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
        }

        /* run in background, if requested */
        if (background && netsnmp_daemonize(1, !syslog))
            exit(1);

        /* initialize tcpip, if necessary */
        SOCK_STARTUP;

        /* initialize the agent library */
        init_agent("example-demon");

        /* initialize mib code here */

        /* mib code: init_nstAgentSubagentObject from nstAgentSubagentObject.C */
        init_nstAgentSubagentObject(); 

        /* initialize vacm/usm access control        */
        if (!agentx_subagent) {
            init_vacm_vars();
            init_usmUser();
        }

        /* example-demon will be used to read example-demon.conf files. */
        /*在這裏讀取一個example-demon.conf的配置文件,這是關鍵*/
        init_snmp("example-demon");

        /* If we're going to be a snmp master agent, initial the ports */
        if (!agentx_subagent)
          init_master_agent();        /* open the port to listen on (defaults to udp:161) */

        /* In case we recevie a request to stop (kill -TERM or kill -INT) */
        keep_running = 1;
        signal(SIGTERM, stop_server);
        signal(SIGINT, stop_server);

        snmp_log(LOG_INFO,"example-demon is up and running.\n");

        /* your main loop here... */
        while(keep_running) {
          /* if you use select(), see snmp_select_info() in snmp_api(3) */
          /*           --- OR ---        */
          agent_check_and_process(1); /* 0 == don't block */
        }

        /* at shutdown time */
        snmp_shutdown("example-demon");
        SOCK_CLEANUP;

        return 0;
}

nstAgentSubagentObject.h

/*
* Note: this file originally auto-generated by mib2c using
*              : mib2c.int_watch.conf,v 5.0 2002/04/20 07:30:13 hardaker Exp $
*/
#ifndef NSTAGENTSUBAGENTOBJECT_H
#define NSTAGENTSUBAGENTOBJECT_H

/*
* function declarations
*/
void                  init_nstAgentSubagentObject(void);

#endif                                /* NSTAGENTSUBAGENTOBJECT_H */

nstAgentSubagentObject.c

/*
* Note: this file originally auto-generated by mib2c using
*              : mib2c.int_watch.conf,v 5.0 2002/04/20 07:30:13 hardaker Exp $
*/

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "nstAgentSubagentObject.h"

/*
* the variable we want to tie an OID to.        The agent will handle all
* * GET and SET requests to this variable changing it's value as needed.
*/

static int  nstAgentSubagentObject = 6;

/*
* our initialization routine, automatically called by the agent
* (to get called, the function name must match init_FILENAME())
*/
void
init_nstAgentSubagentObject(void)
{
          static oid            nstAgentSubagentObject_oid[] =
              { 1, 3, 6, 1, 4, 1, 8072, 2, 4, 1, 1, 2, 0 };

          /*
           * a debugging statement.        Run the agent with -DnstAgentSubagentObject to see
           * the output of this debugging statement.
           */
          DEBUGMSGTL(("nstAgentSubagentObject",
                      "Initializing the nstAgentSubagentObject module\n"));

          /*
           * the line below registers our variables defined above as
           * accessible and makes it writable.        A read only version of any
           * of these registration would merely call
           * register_read_only_int_instance() instead.        The functions
           * called below should be consistent with your MIB, however.
           *
           * If we wanted a callback when the value was retrieved or set
           * (even though the details of doing this are handled for you),
           * you could change the NULL pointer below to a valid handler
           * function.
           */
          DEBUGMSGTL(("nstAgentSubagentObject",
                      "Initalizing nstAgentSubagentObject scalar integer.        Default value = %d\n",
                      nstAgentSubagentObject));

          netsnmp_register_int_instance("nstAgentSubagentObject",
                                        nstAgentSubagentObject_oid,
                                        OID_LENGTH(nstAgentSubagentObject_oid),
                                        &nstAgentSubagentObject, NULL);

          DEBUGMSGTL(("nstAgentSubagentObject",
                      "Done initalizing nstAgentSubagentObject module\n"));
}
編譯鏈接通過!恭喜你!

5、 在C:\usr\etc'\snmp下建立example-demon.conf。內容如下:

#community 的讀寫根據需要設,
rwcommunity        public
agentaddress        161

6、如果開啓snmpd服務,先關閉。啓動上面項目的可執行文件。

7、啓動cmd,執行:

snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.4.1.1.2.0

結果:NET-SNMP-MIB::netSnmp.2.4.1.1.2.0 = INTEGER: 6

snmpset -v1 -c public localhost 1.3.6.1.4.1.8072.2.4.1.1.2.0 i 5

結果:NET-SNMP-MIB::netSnmp.2.4.1.1.2.0 = INTEGER: 5

snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.4.1.1.2.0

結果:NET-SNMP-MIB::netSnmp.2.4.1.1.2.0 = INTEGER: 5

OK!大功告成!

至此,havenzhao http://vcsky.net 我們實現了windows下利用net-snmp擴展。這只是一個最簡單的例子,能夠使用agent接收一個int變量的get/set命令。接下來,我們發現這只是萬里長征的第一步……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章