Net-Snmp多线程以及异步的使用

最近使用到了Net-Snmp来做一个设备信息查询的manager,因为在使用的时候查询的设备以及需要的oid比较多,使用同步的方式一个一个查询会使查询速度慢,所以在这里有两种解决方式。

  1. 多线程

因为刚开始使用Net-snmp不是很熟悉,所以立马想到的就是使用多个线程提高并发。

关于多线程的API,可以在Net-SNMP的rREADME文档看到如下内容:

 

  Traditional                  Single                            Comment

  ===========        ==============            =======

  snmp_sess_init                   snmp_sess_init            Call before either open

  snmp_open                        snmp_sess_open            Single not on Sessions list

                                             snmp_sess_session         Exposes snmp_session pointer

  snmp_send                        snmp_sess_send            Send one APDU

  snmp_async_send            snmp_sess_async_send      Send one APDU with callback

  snmp_select_info              snmp_sess_select_info     Which session(s) have input

  snmp_read                        snmp_sess_read            Read APDUs

  snmp_timeout                    snmp_sess_timeout         Check for timeout

  snmp_close                        snmp_sess_close           Single not on Sessions list

  snmp_synch_response       snmp_sess_synch_response  Send/receive one APDU

      snmp_error                     snmp_sess_error           Get library,system errno

也就是说要想使用多线程的方式去使用NetSNMP的话需要使用SingleAPI,按照文档所说的,使用多线程查询的代码大致如下:

//多线程使用NET-SNMP

#include <iostream>

#include <string>

#include <thread>

#include <vector>



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

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



using namespace std;

const short HOST_COUNT = 3; //主机数

const short OID_COUNT  = 2; //查询的oid数



const char* host_array[3]={

    "192.168.6.1",

    "192.168.6.2",

    "192.168.6.3"

};



const char* oid_array[2]={

    ".1.3.6.1.2.1.1.1.0",      //系统基础信息

    ".1.3.6.1.2.1.1.3.0"       //系统时间

};



typedef struct{

    oid     o[MAX_OID_LEN];

    size_t  l;

}cc_oid;



typedef struct{

    char*               ip;

    void                *pSession;

    vector<cc_oid>      listOid;

    //int                 currentOid;

}Host;



vector<Host> g_vecHosts;



void init_hosts()

{

    for(int i=0; i<HOST_COUNT; i++)

    {

        Host h;

        h.ip = const_cast<char*>(host_array[i]);

        h.listOid.clear();

        for(int j=0; j<OID_COUNT; j++)

        {

            cc_oid o;

            o.l = MAX_OID_LEN;

            if(!read_objid(oid_array[j], o.o, &o.l))

            {

                cout<<"parse oid failed"<<endl;

                return;

            }

            h.listOid.push_back(o);

        }

        g_vecHosts.push_back(h);

    }

}



void init_sessions()

{

    for(int i=0; i<g_vecHosts.size(); i++)

    {

        Host *h = &g_vecHosts[i];

        netsnmp_session session;;



        snmp_sess_init(&session);

        session.peername = const_cast<char*>(host_array[i]);

        session.retries = 0;

        session.timeout = 1000000;

        session.remote_port = 161;

        session.version = SNMP_VERSION_2c;

        session.community = (u_char*)strdup("public");

        session.community_len = strlen("public");

        h->pSession = snmp_sess_open(&session);

        if(!h->pSession)

        {

            cout<<"snmp open failed :"<<host_array[i]<<endl;

        }

    }

}



void get_result(struct snmp_pdu* pdu);

void query(uint index)

{

    netsnmp_pdu* response;

    if(index >= g_vecHosts.size())

    {

        return;

    }

    if(!g_vecHosts[index].pSession)

    {

        cout<<"psession null"<<endl;

        return;

    }

    while(true)

    {

        response = nullptr;

        struct snmp_pdu* pdu = snmp_pdu_create(SNMP_MSG_GET);

        for(auto& o : g_vecHosts[index].listOid)

        {

            snmp_add_null_var(pdu, o.o, o.l);

        }

        int ret = snmp_sess_synch_response(g_vecHosts[index].pSession, pdu, &response);

        if(ret == STAT_SUCCESS && nullptr != response)

        {

            //get result

            cout<<"get result"<<endl;

            get_result(response);

        }

        else

        {



        }

        sleep(1);

    }

    

}



void get_result(struct snmp_pdu* pdu)

{

     struct variable_list *vp = pdu->variables;

    if(vp && pdu->errstat==SNMP_ERR_NOERROR)

    {

        char buf[1024];

        while(vp)

        {

            snprint_variable(buf, sizeof(buf), vp->name, vp->name_length, vp);

            fprintf(stdout, " %s\n", buf);

            vp=vp->next_variable;

        }

    }

}



int main()

{

    SOCK_STARTUP;

    init_snmp("snmpget");    

    init_hosts();

    init_sessions();



    vector<thread> queryThreads;

    for(int i=0; i<g_vecHosts.size(); i++)

    {

        queryThreads.push_back(thread(query, i));

    }



    for(auto &t : queryThreads)

    {

        if(t.joinable())

            t.join();

    }

    SOCK_CLEANUP;

}

运行结果:

 

但是在实际运行过程中总是出现崩溃的现象,查看core文件发现是在snmp_sess_open()函数调用的时候崩溃,但是这个问题只是在运行了一段时间的时候出现,在可以在网上查到对应的解决,连接如下:

https://bugzilla.redhat.com/show_bug.cgi?id=1366282

大致意思是,这是之前Net-SNMP的一个bug,后续版本有解决,需要打补丁。如果有需要的可以找到对应的patch尝试。

 

  1. 异步

考虑到多线程的不确定性,准备尝试使用异步方式完成oid’的查询,而且官方的demo就是使用异步来查询的,貌似Net-Snmp早期的版本也是不支持多线程的。为此封装了部分异步Net-Snmp的接口,如果有需要的可以查看,代码如下:

https://github.com/Icc-o/SnmpManager.git

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值