如何同时保持多个Net-SNMP会话持续开启?
关于Net-SNMP多会话持久化的解决方案
完全可以在程序运行全程保持每个客户端的SNMP会话持续开启,你之前对Net-SNMP会话管理的认知存在偏差——Net-SNMP支持同时维护多个独立的SNMP会话,每个会话对应一个客户端主机,无需关闭旧会话才能开启新会话。
核心实现思路
- 为每个客户端维护独立的
netsnmp_session实例:用容器(比如std::map<std::string, netsnmp_session*>)存储所有会话句柄,键可设为主机IP或名称,便于快速查找。 - 程序启动时批量初始化会话:调用
snmp_sess_open()为每个客户端创建会话,成功后将句柄存入容器。 - 轮询复用已有会话:每分钟轮询时,直接使用容器中保存的会话句柄发起请求,省去重复打开/关闭会话的开销。
- 程序退出统一清理:遍历容器调用
snmp_sess_close()逐一关闭所有会话。
关键注意事项
- 会话故障重连:长时间保持会话可能因网络波动、主机重启导致会话失效,轮询时需检查请求状态,一旦失败则调用
snmp_sess_open()重建会话。 - 独立会话配置:每个会话的版本、社区串、超时时间等参数需独立初始化,避免结构体复用引发的配置冲突。
- 异步API优化:如果客户端数量较多,推荐使用Net-SNMP的异步API(如
snmp_sess_async_send()),可以更高效地处理多会话并发轮询。
简化代码示例
#include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <map> #include <string> #include <vector> // 存储各主机的会话句柄 std::map<std::string, netsnmp_session*> g_sessions; // 初始化单个主机的SNMP会话 netsnmp_session* init_snmp_session(const std::string& host, const std::string& community) { netsnmp_session session_template, *session_ptr; snmp_sess_init(&session_template); session_template.peername = const_cast<char*>(host.c_str()); session_template.community = const_cast<unsigned char*>(community.c_str()); session_template.community_len = community.size(); session_template.version = SNMP_VERSION_2c; session_template.timeout = 1000000; // 1秒超时 session_template.retries = 2; if (!(session_ptr = snmp_sess_open(&session_template))) { snmp_perror("Failed to open session for host"); return nullptr; } return session_ptr; } // 批量初始化所有客户端会话 void init_all_sessions(const std::vector<std::string>& hosts, const std::string& community) { for (const auto& host : hosts) { auto sess = init_snmp_session(host, community); if (sess) { g_sessions[host] = sess; } } } // 轮询单个会话获取IF-MIB数据(以ifInOctets为例) void poll_session(netsnmp_session* sess) { netsnmp_pdu *request_pdu = snmp_pdu_create(SNMP_MSG_GET); if (!request_pdu) return; // 添加要查询的OID:ifInOctets(第一个网络接口) oid if_in_octets[] = {1,3,6,1,2,1,2,2,1,10,1}; snmp_add_var(request_pdu, if_in_octets, OID_LENGTH(if_in_octets), ASN_COUNTER, nullptr); netsnmp_pdu* response_pdu = nullptr; int status = snmp_sess_synch_response(sess, request_pdu, &response_pdu); if (status == STAT_SUCCESS && response_pdu && response_pdu->errstat == SNMP_ERR_NOERROR) { // 处理返回的统计数据 netsnmp_variable_list* vars = response_pdu->variables; if (vars) { // 根据OID类型解析值,此处为计数器类型 u_long in_octets = *vars->val.counter64->high << 32 | *vars->val.counter64->low; printf("Incoming octets: %lu\n", in_octets); } } else { // 会话失效,标记待重建(此处简化处理,实际可加入重连逻辑) printf("Poll failed, session may be invalid\n"); } if (response_pdu) snmp_free_pdu(response_pdu); } // 轮询所有客户端会话 void poll_all_clients() { for (auto& [host, sess] : g_sessions) { printf("Polling host: %s\n", host.c_str()); poll_session(sess); } } // 清理所有会话 void cleanup_sessions() { for (auto& [host, sess] : g_sessions) { snmp_sess_close(sess); } g_sessions.clear(); } int main() { // 初始化SNMP库 init_snmp("snmp_poller"); // 客户端列表示例 std::vector<std::string> hosts = {"192.168.1.10", "192.168.1.11", "192.168.1.12"}; std::string community = "public"; // 初始化所有会话 init_all_sessions(hosts, community); // 模拟每分钟轮询(实际可使用定时器实现) while (true) { poll_all_clients(); sleep(60); } // 清理资源(实际程序退出时执行) cleanup_sessions(); return 0; }
内容的提问来源于stack exchange,提问作者J.Maduka
相关产品推荐
相关产品推荐

