继续来看SNMP,昨天搭了一个测试环境,收到了一票不知道什么含义的数据。
深入了解后,发现这跟一个叫做MIB库的东西有关,这个MIB库是一个非标准的库,每个厂家都有自己的MIB库,据说甚至每个厂家的不同产品可能都不同,学一步做一步,先不管mib库,我先来用java实现一个snmp trap的信息接收demo。
我使用的snmp4j一个开源的工具类
下载地址:https://download.csdn.net/download/formatwindowsxp/10607172
另外这是一个anmp4j的api:https://download.csdn.net/download/formatwindowsxp/10607192
package LOGSYSService_Services.ReceiveServicePack;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Vector;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
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.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
/**
* @author Song
* snmp协议的监听模块,用于监听snmp客户端发来的信息.
* 使用snmp4j实现snmp消息监听,
* snmp4j 版本 2.6.2
* snmp trap 默认端口162
* 2018年08月14日 建立对象
**/
public class ReceiveService_snmp implements CommandResponder//使用snmp4j需要实现一个接口
{
public static void main(String[] args)
{
System.out.println("v1="+MPv1.ID);
System.out.println("v2="+MPv2c.ID);
System.out.println("v3="+MPv3.ID);
ReceiveService_snmp snmp_receive = new ReceiveService_snmp();
snmp_receive.run(); //开始监听
}
//#region 启动程序
public void run()
{
try
{
startListen();
snmp.addCommandResponder(this);
System.out.println("开始监听Trap信息!");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
//#endregion
//#region 启动监听
private static Snmp snmp = null;
private static Address listenAddress;
private static void startListen()
{
try
{
ThreadPool threadPool= ThreadPool.create("Trap", 2);//启动一个线程池,设置最高两个线程
MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
listenAddress = (Address) GenericAddress.parse("udp:0.0.0.0/162"); //监听所有ip的162端口 tcp:0.0.0.0/162
TransportMapping transport = null;
// 对TCP与UDP协议进行处理
try
{
if (listenAddress instanceof UdpAddress)
{
System.out.println("使用UDP协议");
transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
}
else
{
System.out.println("使用TCP协议");
transport = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
}
}
catch (Exception e)
{
System.out.println("接收地址绑定失败,端口162可能被占用,错误信息:"+e.getMessage());
System.exit(0);//绑定失败,停止当前进程
}
snmp = new Snmp(dispatcher, transport);
snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
snmp.listen(); //开始监听
}
catch (Exception e)
{
System.out.println("启动监听时触发catch异常:"+e.getMessage());
}
}
//#endregion
//#region processPdu接口具体的实现
/**
* processPdu接口具体的实现
* 在接收到snmp信息时,会触发这个方法
**/
public void processPdu(CommandResponderEvent respEvnt)
{
if (respEvnt != null && respEvnt.getPDU() != null)
{
Vector<VariableBinding> recVBs = (Vector<VariableBinding>) respEvnt.getPDU().getVariableBindings();//这里提示我类型转换错误,我必须要进行一次强转
System.out.println("=======================消息内容=======================");
System.out.println("数据来源:"+respEvnt.getPeerAddress());
System.out.println("团体名:"+new String(respEvnt.getSecurityName()));//团体名在v1 v2c下可以用来做认证
String snmpVer = respEvnt.getMessageProcessingModel()==0?
"v1":respEvnt.getMessageProcessingModel()==1?
"v2c":respEvnt.getMessageProcessingModel()==3?
"v3":"其他版本";//其实这里还有一个v2u版本,但网上很少提及不知道是不是应用较少?
System.out.println("trap版本:"+snmpVer);
System.out.println(respEvnt.toString());//输出一下整条信息
for (int i = 0; i < recVBs.size(); i++)
{
VariableBinding recVB = recVBs.elementAt(i);
System.out.println("oid:"+recVB.getOid());
System.out.println("variable:"+recVB.getVariable());
}
System.out.println("=======================输出结束=======================");
}
}
//#endregion
}
代码功底有限,见谅,见谅,实现了一个服务器端,尝试一下接收情况,在之前的CentOS的的中执行一下测试命令。
snmp v1版本测试命令
snmptrap -v1 -c public 10.0.0.188 1.3.6.1.4.1.1 10.10.12.219 2 3 1000 1.3.6.1.9.9.44.1.2.1 i 12 1.3.4.1.2.3.1 s test_snmptrap
snmp v2c版本测试命令
snmptrap -v 2c -c public 10.0.0.188“aaa”1.3.6.1.4.1.2345 SNMPv2-MIB :: sysLocation.0 s“just here”
snmp v3版本测试命令
关于v3版本,在安全性上有提高,需要配置认证相关的参数,这里我先搞定1 2版本,后头再来配置这个。
运行命令后,服务端顺利接收到了消息。
消息接收到了,搜索了一下MIB库的相关资料,我是这么想的,MIB库类似一个字典,通过SNMP收到的OID,可以检索到OID对应的内容。按我现在对SNMP的理解,我应该是可以用这几个OID可以确定信息是哪个模块触发的以及事件的详细信息,网上资料比较少,我也是一头雾水,我觉得我现在有两个模式,1。获取设备上的MIB库,然后通过OID比对出对应的信息0.2。使用获取的OID通过SNMP反查得到想要的信息。哪种方式跟符合实际运行情况,我现在也不知道,下面我需要验证一下....