SNMP 使用SNMP4J V2进行同步和异步 GET,SET

重要的类和接口
Snmp类:该类是SNMP4J中最为核心的类。负责SNMP报文的接受和发送。
PDU类和ScopedPDU类:该类是SNMP报文单元的抽象,其中PDU类适用于SNMPv1和SNMPv2c。ScopedPDU类继承于PDU类,适用于SNMPv3。
Target接口和UserTarget类:对应于SNMP代理的地址信息,包括IP地址和端口号(161)。其中Target接口适用于SNMPv1和SNMPv2c。UserTarget类实现了Target接口,适用于SNMPv3。
TransportMapping接口:该接口代表了SNMP4J所使用的传输层协议。这也是SNMP4J一大特色的地方。按照RFC的规定,SNMP是只使用UDP作为传输层协议的。而SNMP4J支持管理端和代理端使用UDP或者TCP进行传输。该接口有两个子接口。

两种消息发送模式
SNMP4J支持两种消息发送模式:同步发送模式和异步发送模式。
其中同步发送模式也称阻塞模式。当管理端发送出一条消息之后,线程会被阻塞,直到收到对方的回应或者时间超时。同步发送模式编程较为简单,但是不适用于发送广播消息。
异步发送模式也称非阻塞模式。当程序发送一条消息之后,线程将会继续执行,当收到消息的回应的时候,程序会对消息作出相应的处理。要实现异步发送模式,需要实例化一个实现了ResponseListener接口的类的对象。ResponseListener接口中有一个名为onResponse的函数。这是一个回调函数,当程序收到响应的时候,会自动调用该函数。由该函数完成对响应的处理。

实现管理端的总体步骤
该部分说明了利用SNMP4J编写SNMP管理端的大致过程,读者在阅读之后会对SNMP4J有一个宏观上的认识。在附录部分,作者给出了一个用SNMP4J开发管理站的样例程序,如果有进一步的需要,请参考附录部分。
初始化
明确SNMP在传输层所使用的协议
一般情况下,我们都使用使用UDP协议作为SNMP的传输层协议,所以我们需要实例化的是一个DefaultUdpTransportMapping接口对象;
实例化一个snmp对象
在此过程中,我们需要将1中实例化的DefaultUdpTransportMapping接口的对象作为参数,穿snmp类的构造函数中。
另外,如果实现的SNMPv3协议,我们还需要设置安全机制,添加安全用户等等;
监听snmp消息
在此,我们可以调用刚刚实例化的DefaultUdpTransportMapping的接口对象的listen方法,让程序监听snmp消息;
构造发送目标
如果实现的是SNMPv3程序,则需要实例化一个UserTarget对象,如果实现的是SNMPv2c或者说SNMPv1,则需要实例化一个CommunityTarget对象。
之后,我们还需要对实例化的对象做一些设置。如果是CommunityTarget的对象,则需要设置版本,重传时间和等待时延。如果是UserTarget对象,我们不仅需要设置版本、重传时间、等待时延,还需要设置安全级别和安全名称。
构造发送报文
如果发送的是SNMPv3的报文,我们则需要实例化一个ScopedPDU    类的对象,否则我们需要实例化一个PDU类的对象。之后,我们还需要生成一个OID对象,其中包含了我们所需要获取的SNMP对象在MIB库中的ID。然后我们需要将OID和之前生成的PDU对象或者是ScopedPDU对象绑定,并且设置PDU的报文类型(五种SNMP报文类型之一)。
构造响应监听对象(异步模式)
当使用异步模式的时候,我们需要实例化一个实现了ResponseListener
的对象,作为响应消息的监听对象。在构造该对象的过程中,我们需要重写ResponseListener的OnResponse函数,该函数是一个回调函数,用来处理程序收到响应后的一些操作。
发送消息
当所有上述操作都设置完毕之后,就可以发送消息了。同步模式和异步模式发送消息调用的函数名字均为send,但是两个函数所需参数不一样。同步模式的参数仅为4.3.2和4.3.3中构造的目标对象和报文对象,而异步模式还需要4.3.4中构造的监听对象。
同步模式发送消息后便等待响应的到达,到达之后会返回一个ResponseEvent对象,该对象中包含了响应的相应信息。
异步模式发送消息之后便会继续执行,当收到响应消息时便会调用监听对象的OnResponse函数。该函数中的语句便是我们对响应的处理!

 

我们来进行一个同步的GET操作,假如你已经有了可以访问的端口:

Java代码    收藏代码
  1. package t1;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Vector;  
  5.   
  6. import org.snmp4j.CommunityTarget;  
  7. import org.snmp4j.PDU;  
  8. import org.snmp4j.Snmp;  
  9. import org.snmp4j.TransportMapping;  
  10. import org.snmp4j.event.ResponseEvent;  
  11. import org.snmp4j.mp.SnmpConstants;  
  12. import org.snmp4j.smi.Address;  
  13. import org.snmp4j.smi.GenericAddress;  
  14. import org.snmp4j.smi.OID;  
  15. import org.snmp4j.smi.OctetString;  
  16. import org.snmp4j.smi.VariableBinding;  
  17. import org.snmp4j.transport.DefaultUdpTransportMapping;  
  18.   
  19. /** 
  20.  * @说明 SNMP4J测试 
  21.  * @author cuisuqiang 
  22.  * @version 1.0 
  23.  * @since 
  24.  */  
  25. public class SnmpUtil {  
  26.     private Snmp snmp = null;  
  27.     private Address targetAddress = null;  
  28.   
  29.     public void initComm() throws IOException {  
  30.         // 设置Agent方的IP和端口  
  31.         targetAddress = GenericAddress.parse("udp:192.168.0.148/22500");  
  32.         TransportMapping transport = new DefaultUdpTransportMapping();  
  33.         snmp = new Snmp(transport);  
  34.         transport.listen();  
  35.     }  
  36.   
  37.     public ResponseEvent sendPDU(PDU pdu) throws IOException {  
  38.         // 设置 目标  
  39.         CommunityTarget target = new CommunityTarget();  
  40.         target.setCommunity(new OctetString("public"));  
  41.         target.setAddress(targetAddress);  
  42.         // 通信不成功时的重试次数 N+1次  
  43.         target.setRetries(2);  
  44.         // 超时时间  
  45.         target.setTimeout(2 * 1000);  
  46.         // SNMP 版本  
  47.         target.setVersion(SnmpConstants.version2c);  
  48.         // 向Agent发送PDU,并返回Response  
  49.         return snmp.send(pdu, target);  
  50.     }  
  51.   
  52.     public void getPDU() throws IOException {  
  53.         // PDU 对象  
  54.         PDU pdu = new PDU();  
  55.         pdu.add(new VariableBinding(new OID("1.2.3.4.5.6")));  
  56.         // 操作类型  
  57.         pdu.setType(PDU.GET);  
  58.         ResponseEvent revent = sendPDU(pdu);  
  59.         if(null != revent){  
  60.             readResponse(revent);  
  61.         }  
  62.     }  
  63.   
  64.     @SuppressWarnings("unchecked")  
  65.     public void readResponse(ResponseEvent respEvnt) {  
  66.         // 解析Response  
  67.         System.out.println("------------>解析Response<-------------");  
  68.         if (respEvnt != null && respEvnt.getResponse() != null) {  
  69.             Vector<VariableBinding> recVBs = respEvnt.getResponse()  
  70.                     .getVariableBindings();  
  71.             for (int i = 0; i < recVBs.size(); i++) {  
  72.                 VariableBinding recVB = recVBs.elementAt(i);  
  73.                 System.out.println(recVB.getOid() + " : "  
  74.                         + recVB.getVariable().toString());  
  75.             }  
  76.         }  
  77.     }  
  78.   
  79.     public static void main(String[] args) {  
  80.         try {  
  81.             SnmpUtil util = new SnmpUtil();  
  82.             util.initComm();  
  83.             util.getPDU();  
  84.         } catch (IOException e) {  
  85.             e.printStackTrace();  
  86.   
  87.         }  
  88.     }  
  89. }  
 

我的被管设备返回了:

Java代码    收藏代码
  1. ------------>解析Response<-------------  
  2. 0.0 : xxx  
  3. 1.3.6.1.2.1.1.6.0 : 12345  
  4. 1.3.6.1.2.1.1.2.0 : 54321  
 

这个GET操作我们只发送了一个OID过去,但是你不能确定会收到多少OID的数据,因为这是双方约定的而不是协议定死的!

消息发送后会产生等待,如果超时时间内没有响应则直接过去!

 

那么异步是怎样实现的呢?其实很简单,只需对上面代码简单修改:

Java代码    收藏代码
  1. package t1;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Vector;  
  5.   
  6. import org.snmp4j.CommunityTarget;  
  7. import org.snmp4j.PDU;  
  8. import org.snmp4j.Snmp;  
  9. import org.snmp4j.TransportMapping;  
  10. import org.snmp4j.event.ResponseEvent;  
  11. import org.snmp4j.event.ResponseListener;  
  12. import org.snmp4j.mp.SnmpConstants;  
  13. import org.snmp4j.smi.Address;  
  14. import org.snmp4j.smi.GenericAddress;  
  15. import org.snmp4j.smi.OID;  
  16. import org.snmp4j.smi.OctetString;  
  17. import org.snmp4j.smi.VariableBinding;  
  18. import org.snmp4j.transport.DefaultUdpTransportMapping;  
  19.   
  20. /** 
  21.  * @说明 SNMP4J测试 
  22.  * @author cuisuqiang 
  23.  * @version 1.0 
  24.  * @since 
  25.  */  
  26. public class SnmpUtil {  
  27.     private Snmp snmp = null;  
  28.     private Address targetAddress = null;  
  29.   
  30.     public void initComm() throws IOException {  
  31.         // 设置Agent方的IP和端口  
  32.         targetAddress = GenericAddress.parse("udp:192.168.0.148/22500");  
  33.         TransportMapping transport = new DefaultUdpTransportMapping();  
  34.         snmp = new Snmp(transport);  
  35.         transport.listen();  
  36.     }  
  37.   
  38.     public ResponseEvent sendPDU(PDU pdu) throws IOException {  
  39.         // 设置 目标  
  40.         CommunityTarget target = new CommunityTarget();  
  41.         target.setCommunity(new OctetString("public"));  
  42.         target.setAddress(targetAddress);  
  43.         // 通信不成功时的重试次数 N+1次  
  44.         target.setRetries(2);  
  45.         // 超时时间  
  46.         target.setTimeout(2 * 1000);  
  47.         // SNMP 版本  
  48.         target.setVersion(SnmpConstants.version2c);  
  49.   
  50.         // 设置监听对象  
  51.         ResponseListener listener = new ResponseListener() {  
  52.             public void onResponse(ResponseEvent event) {  
  53.                 System.out.println("---------->开始异步解析<------------");  
  54.                 readResponse(event);  
  55.             }  
  56.         };  
  57.         // 发送报文  
  58.         snmp.send(pdu, target, null, listener);  
  59.         return null;  
  60.     }  
  61.   
  62.     public void getPDU() throws IOException {  
  63.         // PDU 对象  
  64.         PDU pdu = new PDU();  
  65.         pdu.add(new VariableBinding(new OID("1.2.3.4.5.6")));  
  66.         // 操作类型  
  67.         pdu.setType(PDU.GET);  
  68.         ResponseEvent revent = sendPDU(pdu);  
  69.         if(null != revent){  
  70.             readResponse(revent);  
  71.         }  
  72.     }  
  73.   
  74.     @SuppressWarnings("unchecked")  
  75.     public void readResponse(ResponseEvent respEvnt) {  
  76.         // 解析Response  
  77.         System.out.println("------------>解析Response<-------------");  
  78.         if (respEvnt != null && respEvnt.getResponse() != null) {  
  79.             Vector<VariableBinding> recVBs = respEvnt.getResponse()  
  80.                     .getVariableBindings();  
  81.             for (int i = 0; i < recVBs.size(); i++) {  
  82.                 VariableBinding recVB = recVBs.elementAt(i);  
  83.                 System.out.println(recVB.getOid() + " : "  
  84.                         + recVB.getVariable().toString());  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89.     public static void main(String[] args) {  
  90.         try {  
  91.             SnmpUtil util = new SnmpUtil();  
  92.             util.initComm();  
  93.             util.getPDU();  
  94.         } catch (IOException e) {  
  95.             e.printStackTrace();  
  96.   
  97.         }  
  98.     }  
  99. }  
 

被管设备返回的内容是一样的,但是我们的控制台打印不太一样:

Java代码    收藏代码
  1. ---------->开始异步解析<------------  
  2. ------------>解析Response<-------------  
  3. 0.0 : xxx  
  4. 1.3.6.1.2.1.1.6.0 : 12345  
  5. 1.3.6.1.2.1.1.2.0 : 54321  
 

因为我们采用了异步模式!

 

那么如何SET呢?

我们只需要把操作类型改为SET,然后在UDP中设置参数即可:

Java代码    收藏代码
  1. pdu.add(new VariableBinding(new OID("1.2.3.4.5.6"),new OctetString("priv")));  
  2. // 操作类型  
  3. pdu.setType(PDU.SET);  
 

这里我们传递了一个字符串!打开SNMP4J源码或API,我们看到:

Java代码    收藏代码
  1. /** 
  2.  * Creates an octet string from a java string. 
  3.  * 
  4.  * @param stringValue 
  5.  *    a Java string. 
  6.  */  
  7. public OctetString(String stringValue) {  
  8.   this.value = stringValue.getBytes();  
  9. }  
 

然后我们在源码中还能看到这样的构造函数:

Java代码    收藏代码
  1. /** 
  2.  * Creates an octet string from an byte array. 
  3.  * @param rawValue 
  4.  *    an array of bytes. 
  5.  */  
  6. public OctetString(byte[] rawValue) {  
  7.   this(rawValue, 0, rawValue.length);  
  8. }  
 

其实很简单,因为SNMP4J本身发送的就是一组字节流,你设置的字符串其实在构造中还是获得了这个字符串的字节流信息,其实你完全可以设置一个字节流进去!

 

所以,对于OID的参数,简单来说就是一组BYTE!

<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值