以下可以应用于:Linux、Windows、Mac系统。
我因为网上的文章走了很多弯路,这里如果只是做监听,不需要开启SNMP服务,只需要看下面的代码即可,如果是发出告警是需要开启SNMP服务的。
实现时有以下几个问题需要注意:
1.VMware中配置的SNMP接收方IP和端口,这里的IP是你程序所在服务器的IP,端口一般是162。
注意:要遵循1024 以下的端口要用root启动,这个是windows、Linux、mac通用原则
2.如果本地只是监听消息,不发出消息的话,本地不需要开启SNMP服务。
3.SNMP发出的消息都是通过MIB文件来翻译的,根据OID号来找到对应的消息,即可得到想要的消息,MIB文件也不需要导入到程序中,只需要做对应即可。
在pom.xml文件中引入snmp4j包,如下
<dependency>
<groupId>org.snmp4j</groupId>
<artifactId>snmp4j</artifactId>
<version>2.8.2</version>
</dependency>
以下是代码实现:
import java.io.IOException;
import com.alibaba.fastjson.JSON;
import com.fit2cloud.commons.utils.LogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.MessageDispatcher;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
public class SnmpTrapHandler implements CommandResponder{
private static Logger log = LoggerFactory.getLogger(SnmpTrapHandler.class);
private static int threadNum = 200;
//这里的ip是指程序所在IP,这里是:192.168.0.1
//1162指的是端口号,因为162需要root权限,所以测试的时候我用1162端口,需要两边的IP和端口保持一致
private static String ipAddress = "udp:192.168.0.1/1162";
private Snmp snmp = null;
public void init(){
//1、初始化多线程消息转发类
ThreadPool threadPool = ThreadPool.create("SnmpTrap", threadNum);
MessageDispatcher messageDispatcher = new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
//其中要增加三种处理模型。如果snmp初始化使用的是Snmp(TransportMapping<? extends Address> transportMapping) ,就不需要增加
messageDispatcher.addMessageProcessingModel(new MPv1());
messageDispatcher.addMessageProcessingModel(new MPv2c());
OctetString localEngineID = new OctetString(MPv3.createLocalEngineID());
USM usm = new USM(SecurityProtocols.getInstance().addDefaultProtocols(), localEngineID, 0);
UsmUser user = new UsmUser(new OctetString("SNMPV3"), AuthSHA.ID, new OctetString("authPassword"),
PrivAES128.ID, new OctetString("privPassword"));
usm.addUser(user.getSecurityName(), user);
messageDispatcher.addMessageProcessingModel(new MPv3(usm));
//2、创建transportMapping
TransportMapping<?> transportMapping = null;
try {
UdpAddress updAddr = (UdpAddress) GenericAddress.parse(System.getProperty("snmp4j.listenAddress", ipAddress));
transportMapping = new DefaultUdpTransportMapping(updAddr);
//3、正式创建snmp
snmp = new Snmp(messageDispatcher, transportMapping);
//开启监听
snmp.listen();
} catch (IOException e) {
log.error("初始化transportMapping失败:", e.getMessage());
e.printStackTrace();
}
}
public void start() {
init();
//一定要将当前对象添加至commandResponderListeners中
snmp.addCommandResponder(this);
System.out.println("开始监听trap信息:");
}
/**
* 处理信息方法
*/
@Override
public void processPdu(CommandResponderEvent event) {
String version = null ;
String community = null;
LogUtil.info("接收到的告警信息:"+ JSON.toJSONString(event));
if (event.getPDU().getType() == PDU.V1TRAP) {
version = "v1";
community = new String(event.getSecurityName());
} else if (event.getPDU().getType() == PDU.TRAP){
if (event.getSecurityModel() == 2) {
version = "v2";
community = new String(event.getSecurityName());
}else {
version = "v3";
}
}
System.out.println("接收到的trap信息:[发送来源="+event.getPeerAddress()+",snmp版本="+version+",团体名="+community+", 携带的变量="+event.getPDU().getVariableBindings()+"]");
}
public static void main(String[] args) {
SnmpTrapHandler handler = new SnmpTrapHandler();
handler.start();
}
}