异常现象
java通过snmp4j使用snmpv3连接偶而会出现异常:
org.snmp4j.MessageException: Message processing model 3 returned error: Unknown security name
at org.snmp4j.MessageDispatcherImpl.sendPdu(MessageDispatcherImpl.java:524)
at org.snmp4j.Snmp.sendMessage(Snmp.java:1089)
at org.snmp4j.Snmp.send(Snmp.java:983)
at org.snmp4j.Snmp.send(Snmp.java:963)
at org.snmp4j.Snmp.send(Snmp.java:928)
at java.lang.Thread.run(Thread.java:745)
异常分析
该异常是出现在多线程并发请求,并且每次请求都会创建snmp连接,就可能会出现该异常。
主要是原因下面的代码:
// 生成snmpv3的engineID
byte[] localEngineID = MPv3.createLocalEngineID();
engineId = new OctetString(localEngineID);
USM usm = new USM(SecurityProtocols.getInstance(), engineId, 0);
SecurityModels.getInstance().addSecurityModel(usm);
// 下面省略创建snmp连接代码
Snmp snmp = new Snmp(...);
snmpv3连接需要生成一个engineID作为设备id用来做认证参数,一个设备只需要生成一次就行了,后面的连接都会用到这个engineID。上面代码每次创建连接都会生成一个engineID,并设为全局变量,在并发情况下,如果上个连接还没结束,又创建一个新的连接,就会导致上个连接的engineID失效,然后就会出现这个错误。
解决方式
解决方法很简单,控制 engineId 只生成一次就可以了,可以在静态代码块生成:
static{
// 生成snmpv3的engineID
byte[] localEngineID = MPv3.createLocalEngineID();
engineId = new OctetString(localEngineID);
USM usm = new USM(SecurityProtocols.getInstance(), engineId, 0);
SecurityModels.getInstance().addSecurityModel(usm);
}
也可以在需要的时间生成:
// 省略创建Snmp连接过程
// 如果未生成 engineId,snmp.getUSM()的值为null,
if(snmp.getUSM() == null){
// 生成snmpv3的engineID
byte[] localEngineID = MPv3.createLocalEngineID();
engineId = new OctetString(localEngineID);
USM usm = new USM(SecurityProtocols.getInstance(), engineId, 0);
SecurityModels.getInstance().addSecurityModel(usm);
}