You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

端口1161的SNMP Agent:Net-SNMP查询超时问题排查

自定义PySNMP Agent无响应问题的修复方案

修复后的完整Agent代码

from pysnmp.hlapi import *
from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413 import cmdrsp, context
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.smi import exval
import psutil

# 创建SNMP引擎
snmpEngine = engine.SnmpEngine()

# 自定义MIB对应的OID
CPU_OID = '1.3.6.1.4.1.9999.2'  # MY-MIB::cpuUtil
MEMORY_OID = '1.3.6.1.4.1.9999.1'  # MY-MIB::memoryUtil
DISK_OID = '1.3.6.1.4.1.9999.3'  # MY-MIB::diskUtil

def get_cpu_usage():
    """CPU使用率(百分比)"""
    return int(psutil.cpu_percent(interval=1))

def get_memory_usage():
    """内存使用率(百分比)"""
    memory = psutil.virtual_memory()
    return int(memory.used * 100 / memory.total)

def get_disk_usage():
    """磁盘使用率(主分区,百分比)"""
    disk = psutil.disk_usage('/')
    return int(disk.used * 100 / disk.total)

def create_variable_binds(oid, value):
    return [ObjectType(ObjectIdentity(oid), Integer32(value))]

def create_snmp_agent():
    """监听GET请求的SNMP Agent"""
    
    def process_snmp_request(snmpEngine, stateReference, contextEngineId, contextName, varBinds, cbCtx):
        """处理SNMP GET请求"""
        oid, = [x[0] for x in varBinds]
        oid_str = str(oid)
    
        print("收到请求OID:", oid_str)
    
        # 精确匹配OID,避免前缀匹配误判
        if oid_str == CPU_OID:
            value = get_cpu_usage()
            varBinds = create_variable_binds(oid, value)
        elif oid_str == MEMORY_OID:
            value = get_memory_usage()
            varBinds = create_variable_binds(oid, value)
        elif oid_str == DISK_OID:
            value = get_disk_usage()
            varBinds = create_variable_binds(oid, value)
        else:
            # 未知OID返回标准SNMP错误
            varBinds = [(oid, exval.noSuchInstance)]
        
        cmdrsp.sendVarBinds(snmpEngine, stateReference, contextEngineId, contextName, varBinds, cbCtx)

    # 配置SNMPv2c社区字符串(必须步骤,否则Agent无法识别合法请求)
    config.addCommunity(
        snmpEngine,
        1,  # SNMPv2c对应的mpModel值
        'public',  # 社区字符串
        'my-area'  # 安全名称标识
    )
    
    # 注册默认上下文(SNMPv2c默认使用空字符串作为上下文名称)
    snmpContext = context.SnmpContext(snmpEngine)
    snmpContext.registerContextName(v2c.OctetString(), process_snmp_request)
    
    # 配置UDP传输,监听127.0.0.1:1161
    config.addTransport(
        snmpEngine,
        udp.domainName,
        udp.UdpTransport().openServerMode(('127.0.0.1', 1161))
    )

    print("SNMP Agent已启动,监听127.0.0.1:1161...")
    snmpEngine.transportDispatcher.jobStarted(1)

    try:
        snmpEngine.transportDispatcher.runDispatcher()
    except:
        snmpEngine.transportDispatcher.closeDispatcher()
        raise

if __name__ == "__main__":
    create_snmp_agent()

问题根源分析

原代码存在两个致命问题:

  1. 社区字符串未正确配置:
    原代码直接将CommunityData传给GetCommandResponder,但PySNMP需要通过config.addCommunity显式配置社区字符串,否则Agent会忽略所有未授权的请求。
  2. 上下文名称不匹配:
    原代码注册了名为public的上下文,但SNMPv2c协议默认使用空字符串作为上下文名称,导致请求无法匹配到处理器,自然不会返回响应。

验证步骤

  1. 启动修复后的Agent:
    python3 my_snmp-agent.py
    
  2. 执行测试命令:
    snmpget -v2c -c public 127.0.0.1:1161 1.3.6.1.4.1.9999.1
    
  3. 预期输出示例:
    MY-MIB::memoryUtil = INTEGER: 38
    

额外优化说明

  • 将OID前缀匹配改为精确匹配,避免误判;
  • 对未知OID返回noSuchInstance标准错误,符合SNMP协议规范;
  • 明确标注SNMPv2c对应的mpModel值(1对应SNMPv2c)。

内容的提问来源于stack exchange,提问作者Simon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:15:13