采用Java进行SNMP通信的指南第1页/共13页Java进行SNMP通信的指南采用Java进行SNMP通信的指南第2页/共13页1.概述在网络通信中,我们会经常遇到支持SNMP协议的网络设备打交道,支持SNMP协议的网络设备有很多,如各种带操作系统的服务器、路由器、交换机等,装有UNIX操作系统中的服务器一般都会支持SNMP协议,Windows操作系统的服务器也可以通过”控制面板-添加/删除程序-添加/删除Windows组件-管理和监视工具”中安装SNMP组件,如下图所示。图1-1本文的目的不在于讲解SNMP的原理,关于SNMP的原理及其信息组织结构MIB的详细资料,网上的资料很多,本文的目的就是针对在Java环境下解决如何实现SNMP客户端的调用操作以及如何实现SNMP服务器的简单模拟,把笔者的一些经验分享给大家。2.实现过程我们知道,SNMP协议是基于UDP协议的,RFC-1157就是SNMP协议详细规范,SNMP协议经历了3个版本,分别是SNMPV1、SNMPV2和SNMPV3。SNMPV1是一种简单的请求/响应协议,网络管理系统发出一个请求,管理器则返回一个响应,支持GET、GETNEXT、SET和TRAP这4种操作;SNMPV2在SNMPV1的基础上还新增了两种新操作,GETBULK和INFORM;SNMPV3中增加了安全管理方式及远程控制。由于SNMPV3的安全控制设置起来比较麻烦,所以一些被管设备不支持SNMPV3,而SNMPV1对于大数据量处理有缺陷,所以大部分被管设备都支持SNMPV2,应用得比较多的也是SNMPV2。JDK提供了对于UDP的编程的支持,分别是数据报套接字(DatagramSocket)和数据包(DatagramPacket),直接采用这些类可以实现对SNMP协议的操作调用,但是正如西方国采用Java进行SNMP通信的指南第3页/共13页家一句谚语“不要重复发明轮子(Don’tReinventtheWheel)”,我们没有必要从头开始在设计如何通过Java来实现SNMP,开源源代码的阵营里有好多工具包已经帮我们做掉这件事情了,其中比较出名的有joeSNMP、SNMP4J、iReasoningJavaSNMPAPI等,笔者采用的是SNMP4J,利用SNMP4J可以实现多种SNMP的应用,如客户端调用、Trap的收发、服务端模拟,下面我们就详细讲解如何通过SNMP4J来实现客户端及模拟器(服务端)的应用。2.1.SNMP4J介绍我们用到了SNMP4J的几个基础类:org.snmp4j.TransportMapping;org.snmp4j.Snmp;org.snmp4j.smi.Address;org.snmp4j.Target;TransportMapping类是对传输层的封装,对UDP封装为DefaultUdpTransportMapping,TCP封装为DefaultTcpTransportMapping,TransportMapping只定义传输的接口,由于SNMP默认采用UDP作为传输协议,所以笔者感觉DefaultTcpTransportMapping不会被用到。Snmp类是SNMP4J的核心,它提供了发送和接收SNMPPDUs的方法,所有的SNMPPDU类型都可以采用同步或者异步的方式被发送。PDU.javaimplementsBERSerializable//SNMPv2的报文,提供了编码时需要的信息(个人觉得编码信息可以由工具类提供,对用户会混淆)。报文结构参见=146。主要子类PDUv1,ScopedPDU(v3)。AddressIP地址和端口(和java.net的不同),常用实现是UdpAddress。Target发送的时候要用到,包含Address,超时、重试次数、SNMP的版本,常用实现是ComunityTarget,可以指定readcommunity及writecommunity。2.2.实现客户端2.2.1.初始化首先定义类变量,DATATYPE常量的定义是在SET操作里用到的,代码如下:代码:/**TransportMapping*/privateTransportMappingtransport;/**プロトコール*/privateSnmpprotocol;/*DateType定義*//**Counter32*/publicstaticfinalintDATATYPE_COUNTER32=0;/*Counter64*/publicstaticfinalintDATATYPE_COUNTER64=1;采用Java进行SNMP通信的指南第4页/共13页/**Gauge32*/publicstaticfinalintDATATYPE_GAUGE32=2;/**GenericAddress*/publicstaticfinalintDATATYPE_GENERICADDRESS=3;/**Integer32*/publicstaticfinalintDATATYPE_INTEGER32=4;/**IpAddress*/publicstaticfinalintDATATYPE_IPADDRESS=5;/**OctetString*/publicstaticfinalintDATATYPE_OCTETSTRING=6;/**TimeTicks*/publicstaticfinalintDATATYPE_TIMETICKS=7;/**UnsignedInteger32*/publicstaticfinalintDATATYPE_UNSIGNEDINTEGER32=8;代码段2.2.1-1初始化,代码如下:代码:/***初期化**@throwsSmsTerminalException*アプリエラー*/privatevoidinit()throwsSmsTerminalException{try{transport=newDefaultUdpTransportMapping();protocol=newSnmp(transport);}catch(IOExceptionex){thrownewSmsTerminalException(initerror,Constants.EXIT_CODE_NORMAL,ex);}}代码段2.2.1-22.2.2.GET/GETNEXT操作SnmpVO是一个简单的JavaBean,包含了以下属性ipAddress(目标机器IP地址);port(端口);retry(重试次数);timeout(超时时间);oid(要获取属性的OID);type(操作类型,默认是GET);communityGet(GET操作的团体字符串);communitySet(SET操作的团体字符串);GET/GETNEXT操作的代码如下:代码:/***MIB情報を取得する采用Java进行SNMP通信的指南第5页/共13页**@paramsnmpVo*SNMP相関情報*@returnoutValue*SNMP取得結果**@throwsSmsTerminalException*アプリエラー*/publicStringgetSnmpValue(SnmpVOsnmpVo)throwsSmsTerminalException{log.debug(getSnmpValuestart);StringoutValue=;try{CommunityTargetmyTarget=setTarget(snmpVo,false);transport.listen();PDUrequest=setRequest(snmpVo);PDUresponse=null;//PDUresponseResponseEventresponseEvent=protocol.send(request,myTarget);if(snmpSendReceiveListener!=null){snmpSendReceiveListener.beforeReceive();}//SNMP受信response=responseEvent.getResponse();if(response!=null){if(response.getErrorIndex()==PDU.noError&&response.getErrorStatus()==PDU.noError){//正常場合VariableBindingvb=response.get(0);if(vb.isException()){thrownewSmsTerminalException(vb.getVariable().toString(),Constants.EXIT_CODE_NORMAL,responseEvent.getError());}outValue=vb.getVariable().toString();}else{//エラー発生thrownewSmsTerminalException(responseEvent.getError().getMessage(),Constants.EXIT_CODE_NORMAL,responseEvent.getError());}}else{//タイムアウトthrownewSmsTerminalTimeoutException(SNMP受信タイムアウト);}}catch(IOExceptionex){thrownewSmsTerminalException(getSnmpValueIOerror,Constants.EXIT_CODE_NORMAL,ex);}finally{try{if(protocol!=null){采用Java进行SNMP通信的指南第6页/共13页protocol.close();}if(transport!=null&&transport.isListening()){transport.close();}}catch(IOExceptionex){thrownewSmsTerminalException(closeprotocolortransporterror,Constants.EXIT_CODE_NORMAL,ex);}}log.debug(getSnmpValueend);returnoutValue;}代码段2.2.2-1其中用到了setTarget方法,采用ComunityTarget设置目标设备IP和端口、Community、SNMP版本、重试次数、超时时间,代码如下:代码:/***CommunityTargetの設定**@paramsnmpVo*SNMP相関情報*@paramisSetOperationSET操作かどうか*@returnmyTarget*設定したCommunityTarget**/privateCommunityTargetsetTarget(SnmpVOsnmpVo,booleanisSetOperation){CommunityTargetmyTarget=newCommunityTarget();AddressdeviceAdd;deviceAdd=GenericAddress.parse(snmpVo.getIpAddress()+/+snmpVo.getPort());myTarget.setAddress(deviceAdd);//addressif(isSetOperation){if(StringConverter.nullCheckString(snmpVo.getCommunitySet())){myTarget.setCommunity(newOctetString(snmpVo.getCommunitySet()));//communitySet}}else{if(Str