SNMP协议还算简单
其实针对协议的开发我们只要知道协议的内容,然后架起Socket服务器,然后用字符串拼出协议内容格式的字符串,使用Socket进行通信就好了。
针对协议的开源包主要把这些过程封装了。比如SNMP协议。
我们只需要针对PDU对象编程,然后SNMP4j就会把PDU对象转化为SNMP4j协议的格式,进行BER编码,然后传输,最后解码,再翻译为PDU对象。
先看一下SNMP协议要传输的内容:
http://www.cnpaf.net/Class/SNMP/200408/43.html
这个文章中说的很全和好了。接下来就是用SNMP4J协议的jar包来完成各个功能。
http://www.snmp4j.org/html/download.html
在这个网址中下载最新的SNMP4J的jar包,
或者是这个链接下载http://download.csdn.net/detail/three_man/7478029
顺便可以把SNMP4J-Agent-2.2-Instrumentation-Guide.pdf 这个文档描述了对Agent进行开发。
这个文档的下载链接:http://download.csdn.net/detail/three_man/7477953
SNMP4J把开发包分为了两个,一个SNMP4J.jar主要负责get,trap,set,一个是SNMP4J-Agent.jar主要负责作为一个网元被管理。
1 首先说一下怎么开发一个Agent.
需要用到两个配置文件bc和cfg文件,可以在这里下载:http://download.csdn.net/detail/three_man/7477991
大概的代码为:
import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.snmp4j.agent.BaseAgent; import org.snmp4j.agent.CommandProcessor; import org.snmp4j.agent.DuplicateRegistrationException; import org.snmp4j.agent.io.ImportModes; import org.snmp4j.agent.mo.DefaultMOTable; import org.snmp4j.agent.mo.MOTableRow; import org.snmp4j.agent.mo.snmp.RowStatus; import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB; import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB; import org.snmp4j.agent.mo.snmp.SnmpTargetMIB; import org.snmp4j.agent.mo.snmp.StorageType; import org.snmp4j.agent.mo.snmp.VacmMIB; import org.snmp4j.agent.security.MutableVACM; import org.snmp4j.mp.MPv3; import org.snmp4j.security.SecurityLevel; import org.snmp4j.security.SecurityModel; import org.snmp4j.security.USM; import org.snmp4j.smi.Integer32; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; import org.snmp4j.smi.Variable; public class MyAgent extends BaseAgent { private List<DefaultMOTable> moTables = new ArrayList<DefaultMOTable>(); private String community; protected MyAgent(File bootCounterFile, File configFile, List<DefaultMOTable> moTables, String community) { super(bootCounterFile, configFile, new CommandProcessor(new OctetString(MPv3.createLocalEngineID()))); this.moTables = moTables; this.community = community; } @Override protected void registerManagedObjects() { try { for (DefaultMOTable table : moTables) { server.register(table, null); } } catch (DuplicateRegistrationException e) { e.printStackTrace(); } } public void startUp(){ try { this.init(); } catch (IOException e) { e.printStackTrace(); } this.loadConfig(ImportModes.REPLACE_CREATE); this.addShutdownHook(); this.getServer().addContext(new OctetString(community)); this.finishInit(); this.run(); this.sendColdStartNotification(); } /** * to set community */ @Override protected void addCommunities(SnmpCommunityMIB communityMIB) { Variable[] com2sec = new Variable[] { new OctetString(community), // community name new OctetString("cpublic"), // security name getAgent().getContextEngineID(), // local engine ID new OctetString(community), // default context name new OctetString(), // transport tag new Integer32(StorageType.nonVolatile), // storage type new Integer32(RowStatus.active) // row status }; MOTableRow row = communityMIB.getSnmpCommunityEntry().createRow( new OctetString("public2public").toSubIndex(true), com2sec); communityMIB.getSnmpCommunityEntry().addRow(row); } }
- 主要的代码是需要继承BaseAgent
- 需要设置community
- 需要注册Table,这个注册中的内容将是供给get和walk的内容。
- 可以从MIB直接构建Agent,可能需要的包为:mibble-mibs是能够独MIB结构。这个也提供个下载地址吧: http://download.csdn.net/detail/three_man/7478061
2. Trap Receiver
import java.io.IOException; import java.util.logging.Logger; import org.snmp4j.MessageDispatcherImpl; import org.snmp4j.Snmp; import org.snmp4j.TransportMapping; import org.snmp4j.mp.MPv2c; import org.snmp4j.smi.Address; import org.snmp4j.smi.GenericAddress; import org.snmp4j.smi.UdpAddress; import org.snmp4j.transport.DefaultUdpTransportMapping; import org.snmp4j.util.MultiThreadedMessageDispatcher; import org.snmp4j.util.ThreadPool; import com.prince.snmp.tool.Command; import com.prince.snmp.tool.util.Configure; import com.prince.snmp.tool.util.Const; /** * 构建一个多线程的Trap Receiver * @author wangzijian * */ public class SnmpReceiver implements Command{ private final Logger log = Logger.getLogger(SnmpReceiver.class.getName()); @Override public void startUp() throws IOException { log.info("Snmp Trap Receiver Start"); log.info("listened on " + Configure.getInstance().getUdpTrapIpPort()); ThreadPool pool = ThreadPool.create(Const.THREAD_POOL_NAME, Const.AGENT_THREAD_NUM); MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(pool, new MessageDispatcherImpl()); Address listenAddress = GenericAddress.parse(Configure.getInstance().getUdpTrapIpPort()); TransportMapping transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress); // 构建SNMP,并且使其开始监听 Snmp snmp = new Snmp(dispatcher, transport); snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c()); snmp.listen(); snmp.addCommandResponder(new CommandResponderImpl()); } }
package com.prince.snmp.tool.receiver; import java.util.List; import java.util.logging.Logger; import org.snmp4j.CommandResponder; import org.snmp4j.CommandResponderEvent; import org.snmp4j.PDU; import org.snmp4j.smi.OID; import org.snmp4j.smi.VariableBinding; public class CommandResponderImpl implements CommandResponder { private final Logger log = Logger.getLogger(CommandResponderImpl.class.getName()); @Override public void processPdu(CommandResponderEvent event) { PDU pdu = event.getPDU(); if(PDU.TRAP == pdu.getType()){ operate(pdu); }else{ log.info("pdu method is:" + pdu.getType() + " not a trap"); } } private void operate(PDU pdu) { List<VariableBinding> bindings = pdu.getBindingList(new OID(".1")); for (VariableBinding binding : bindings) { System.out.println(binding.getOid() + "====" + binding.getVariable().toString()); } } }
- 需要一个多线程的服务器MultiThreadedMessageDispatcher
- 还需要一个处理类 CommandResponderImpl snmp.addCommandResponder
- 在处理类中能够得到PDU,这个类不只可以作为Receiver还能够开发为Agent,但是需要自己来写很多逻辑,还有可能用到文件或者内存数据库
package com.prince.snmp.tool.trap; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Vector; import org.snmp4j.CommunityTarget; import org.snmp4j.PDU; import org.snmp4j.Snmp; import org.snmp4j.TransportMapping; import org.snmp4j.event.ResponseEvent; import org.snmp4j.smi.Address; import org.snmp4j.smi.GenericAddress; import org.snmp4j.smi.OctetString; import org.snmp4j.smi.UdpAddress; import org.snmp4j.smi.VariableBinding; import org.snmp4j.transport.DefaultUdpTransportMapping; import com.prince.snmp.tool.Command; import com.prince.snmp.tool.trap.dataGenerator.ITrapGenerator; import com.prince.snmp.tool.util.Configure; public class TrapSender implements Command{ private Snmp snmp; private Address targetAddress; private ITrapGenerator generator; public TrapSender(ITrapGenerator generator) { this.generator = generator; targetAddress = GenericAddress.parse(Configure.getInstance().getUdpTrapIpPort()); TransportMapping<UdpAddress> transport = null; try { transport = new DefaultUdpTransportMapping(); snmp = new Snmp(transport); transport.listen(); } catch (IOException e) { e.printStackTrace(); } } public void sendTrap(){ CommunityTarget target = new CommunityTarget(); target.setAddress(targetAddress); target.setRetries(Configure.getInstance().getRetries()); target.setTimeout(Configure.getInstance().getTimeOut()); target.setCommunity(new OctetString(Configure.getInstance().getCommunity())); target.setVersion(Configure.getInstance().getSnmpVersion()); List<TrapData> datas = generator.generateTrapData(); try { for (TrapData trapData : datas) { sendPdu(trapData, target); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void sendPdu(TrapData trapData, CommunityTarget target) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException { PDU pdu = MoToPdu.moToPdu(trapData); ResponseEvent respEvnt = snmp.send(pdu, target); // 解析Response if (respEvnt != null && respEvnt.getResponse() != null) { Vector<VariableBinding> recVBs = (Vector<VariableBinding>) respEvnt.getResponse().getVariableBindings(); for (int i = 0; i < recVBs.size(); i++) { VariableBinding recVB = recVBs.elementAt(i); System.out.println(recVB.getOid() + " : " + recVB.getVariable()); } } } }
- trap主要注意必须设置两个VariableBingding
pdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(trap.getSysUpTime())));
pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID(trap.getTrapOid())))
4. getprivate static void simpleGet() throws IOException { TransportMapping<UdpAddress> transport = new DefaultUdpTransportMapping(); Snmp snmp = new Snmp(transport); transport.listen(); CommunityTarget target = new CommunityTarget(); target.setCommunity(new OctetString("CONV")); Address targetAddress = GenericAddress.parse("udp:10.141.43.237/161"); target.setAddress(targetAddress); target.setRetries(3); target.setTimeout(3000); target.setVersion(SnmpConstants.version2c); PDU pdu = new PDU(); pdu.add(new VariableBinding(new OID(".1.3.6.1.4.1.7569.1.2.1.23.3.1"))); pdu.setType(PDU.GETBULK); pdu.setMaxRepetitions(20); pdu.setNonRepeaters(0); ResponseEvent respEvnt = snmp.send(pdu, target); if (respEvnt != null && respEvnt.getResponse() != null) { Vector<VariableBinding> recVBs = (Vector<VariableBinding>) respEvnt.getResponse().getVariableBindings(); for (int i = 0; i < recVBs.size(); i++) { VariableBinding recVB = recVBs.elementAt(i); System.out.println(recVB.getOid() + " : " + recVB.getVariable()); } } }
- get相对于比较简单,资料也比较多。主要是设定pdu.setType(PDU.GETBULK);
- 利用getnext和一些判断可以实现walk.
- http://blog .sina.com.cn/s/blog_6cb15f8f0100yx4p.html 这个哥们儿写得非常好
具体的代码没有写,因为下一篇会共享一个小的工具,可以以配置文件为基础来构建Receiver,发送Trap,构建Agent等。