一、前言

之前有在弄监控服务器这块的工作,今天来整体总结下。因为有些服务器(路由器、交换机等都是基于snmp协议的)必须使用snmp协议去监控采集和接收信息,所以必须去了解snmp相关内容,以及如何在基于java上开发。关于了解snmp相关内容,必看《SNMP简单网络管理协议》这本书里面介绍的很详细,另外推荐这位前辈的博文写的很到位《snmp学习总结》。关于snmp4j的介绍也可以看看前面这位前辈关于《snmp学习总结》的最后一篇博文《snmp4j介绍》。当然本篇主要记录如何基于Java如何使用snmp4j去开发实现监控与采集,下面我们直接结合源码以及实例讲解:

二、针对源码进行分析:

  1、核心对象SNMP的初始化。

  源码中有四种初始化方法及四个构造函数,其实都大同小异:参数少的就必须后续添加,参数多的必须提前初始化。
       

  我们先看看第一个无参构造函数,源码很简单,但是注释很多,所以看源码必须要先看注释。

  1. /**
  2. * Creates a {@code Snmp} instance that uses a
  3. * {@code MessageDispatcherImpl} with no message processing
  4. * models and no security protols (by default). You will have to add
  5. * those by calling the appropriate methods on
  6. * {@link #getMessageDispatcher()}.
  7. * <p>
  8. * At least one transport mapping has to be added before {@link #listen()}
  9. * is called in order to be able to send and receive SNMP messages.
  10. * <p>
  11. * To initialize a {@code Snmp} instance created with this constructor
  12. * follow this sample code:
  13. * <pre>
  14. 14 * Transport transport = ...;
  15. 15 * Snmp snmp = new Snmp();
  16. 16 * SecurityProtocols.getInstance().addDefaultProtocols();
  17. 17 * MessageDispatcher disp = snmp.getMessageDispatcher();
  18. 18 * disp.addMessageProcessingModel(new MPv1());
  19. 19 * disp.addMessageProcessingModel(new MPv2c());
  20. 20 * snmp.addTransportMapping(transport);
  21. 21 * OctetString localEngineID = new OctetString(
  22. 22 * MPv3.createLocalEngineID());
  23. 23 * // For command generators, you may use the following code to avoid
  24. 24 * // engine ID clashes:
  25. 25 * // MPv3.createLocalEngineID(
  26. 26 * // new OctetString("MyUniqueID"+System.currentTimeMillis())));
  27. 27 * USM usm = new USM(SecurityProtocols.getInstance(), localEngineID, 0);
  28. 28 * disp.addMessageProcessingModel(new MPv3(usm));
  29. 29 * snmp.listen();
  30. * </pre>
  31. */
  32. public Snmp() {
  33. this.messageDispatcher = new MessageDispatcherImpl();
  34. if (SNMP4JSettings.getSnmp4jStatistics() != SNMP4JSettings.Snmp4jStatistics.none) {
  35. counterSupport = CounterSupport.getInstance();
  36. }
  37. }

  从上面注释中可以看出要初始化snmp需要设置messageDispatcher里面的参数和TransportMapping参数,如果没有设置好这个两个参数,发送报文时会报错(见下面案例).所以我们可以直接使用第三个构造函数。

  接下来我们来看第二个构造函数Snmp(TransportMapping<? extends Address> transportMapping):

  1. /**
  2. * Creates a <code>Snmp</code> instance that uses a
  3. * <code>MessageDispatcherImpl</code> with all supported message processing
  4. * models and the default security protols for dispatching.
  5. * <p>
  6. * To initialize a <code>Snmp</code> instance created with this constructor
  7. * follow this sample code:
  8. * <pre>
  9. * Transport transport = ...;
  10. * Snmp snmp = new Snmp(transport);
  11. * OctetString localEngineID =
  12. * new OctetString(snmp.getMPv3().getLocalEngineID());
  13. * USM usm = new USM(SecurityProtocols.getInstance(), localEngineID, 0);
  14. * SecurityModels.getInstance().addSecurityModel(usm);
  15. * snmp.listen();
  16. * </pre>
  17. *
  18. * @param transportMapping TransportMapping
  19. * the initial <code>TransportMapping</code>. You can add more or remove
  20. * the same later.
  21. */
  22. public Snmp(TransportMapping<? extends Address> transportMapping) {
  23. this();
  24. initMessageDispatcher();
  25. if (transportMapping != null) {
  26. addTransportMapping(transportMapping);
  27. }
  28. }
  1. protected final void initMessageDispatcher() {
  2. this.messageDispatcher.addCommandResponder(this);
  3. this.messageDispatcher.addMessageProcessingModel(new MPv2c());
  4. this.messageDispatcher.addMessageProcessingModel(new MPv1());
  5. this.messageDispatcher.addMessageProcessingModel(new MPv3());
  6. SecurityProtocols.getInstance().addDefaultProtocols();
  7. }

  从源码中可以看到它帮我们设置了messageDispatcher里面的参数,只要我们提供TransportMapping参数即可。第四个构造函数Snmp(MessageDispatcher messageDispatcher)其实跟第一个类似同样需要提供两个参数,所以第三个和第四个就列出来了。其中涉及到接口有MessageDispatcher接口、MessageProcessingModel接口,涉及到的类有MPv1、MPv2和MPv3分别对应snmp版本v1、v2c和v3。

  1. /**
  2. * @description MessageDispatcher接口定义了处理传入的SNMP消息并将其分派到感兴趣的CommandResponder实例的实例的公共服务。它还提供了一个发送出去的SNMP消息的服务。
  3. */
  4. public interface MessageDispatcher extends TransportListener {}
  5. /**
  6. * @description MessageProcessingModel 接口为所有SNMP消息处理模型定义了通用方法。
  7. */
  8. public interface MessageProcessingModel {}
  9. /**
  10. * @description TransportMapping定义了SNMP传输映射的公共接口。传输映射只能支持单个传输协议。
  11. */
  12. public interface TransportMapping<A extends Address> {}

  2、核心对象Target

  我们先看下Target对象下的继承关系。其中主要用到的子对象是CommunityTarget和UserTarget,CommunityTarget用于SNMPv1和SNMPv2c这两个版本,而UserTarget用于SNMPV3版本。

  在初始化CommunityTarget时默认使用的是snmpv1(适用于snmpv2).

  1. /**
  2. * Default constructor.
  3. */
  4. public CommunityTarget() {
  5. setVersion(SnmpConstants.version1);
  6. setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
  7. setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1);
  8. }

  3、核心对象PDU

  

  跟Target一样,针对snmp的不同版本是使用不同的子类去实现。PDUv1用于SNMPv1和SNMPv2c这两个版本,而ScopedPDU用于SNMPV3版本。

三、案例分析:

  1、snmpGet功能测试:

  第一步:要初始snmp并开启监听。其中有点不同的是,为了支持snmpv3版本的处理需要增加用户并设置安全名称和加密算法。(关于那些静态变量的值,最好放到配置文件中显得灵活点)。

另外再说明下:snmp是基于udp协议发送报文的,且snmp端口默认为161。

  1. public class SnmpUtil {
  2. private static Logger log = LoggerFactory.getLogger(SnmpUtil.class);
  3. public static Snmp snmp = null;
  4. private static String community = "public";
  5. private static String ipAddress = "udp:10.10.112.105/";
  6.  
  7. /**
  8. * @description 初始化snmp
  9. * @author YuanFY
  10. * @date 2017年12月16日 上午10:28:01
  11. * @version 1.0
  12. * @throws IOException
  13. */
  14. public static void initSnmp() throws IOException{
  15. //1、初始化多线程消息转发类
  16. MessageDispatcher messageDispatcher = new MessageDispatcherImpl();
  17. //其中要增加三种处理模型。如果snmp初始化使用的是Snmp(TransportMapping<? extends Address> transportMapping) ,就不需要增加
  18. messageDispatcher.addMessageProcessingModel(new MPv1());
  19. messageDispatcher.addMessageProcessingModel(new MPv2c());
  20. //当要支持snmpV3版本时,需要配置user
  21. OctetString localEngineID = new OctetString(MPv3.createLocalEngineID());
  22. USM usm = new USM(SecurityProtocols.getInstance().addDefaultProtocols(), localEngineID, 0);
  23. UsmUser user = new UsmUser(new OctetString("SNMPV3"), AuthSHA.ID, new OctetString("authPassword"),
  24. PrivAES128.ID, new OctetString("privPassword"));
  25. usm.addUser(user.getSecurityName(), user);
  26. messageDispatcher.addMessageProcessingModel(new MPv3(usm));
  27. //2、创建transportMapping
  28. UdpAddress updAddr = (UdpAddress) GenericAddress.parse("udp:10.10.112.177/161");
  29. TransportMapping<?> transportMapping = new DefaultUdpTransportMapping(updAddr);
  30. //3、正式创建snmp
  31. snmp = new Snmp(messageDispatcher, transportMapping);
  32. //开启监听
  33. snmp.listen();
  34. }
  35. }

  其中要注意的是UdpAddress updAddr = (UdpAddress) GenericAddress.parse("udp:10.10.112.177/161"); 只能指定本机ip,要么不要设置地址。请看DefaultUdpTransportMapping的源码

  1. /**
  2. * Creates a UDP transport on the specified address. The address will not be
  3. * reused if it is currently in timeout state (TIME_WAIT).
  4. *
  5. * @param udpAddress
  6. * the local address for sending and receiving of UDP messages.
  7. * @throws IOException
  8. * if socket binding fails.
  9. */
  10. public DefaultUdpTransportMapping(UdpAddress udpAddress) throws IOException {
  11. super(udpAddress);
  12. socket = new DatagramSocket(udpAddress.getPort(),
  13. udpAddress.getInetAddress());
  14. }

  第二步: 根据snmp版本创建Target对象,其中针对snmpV3版本需要设置安全级别和安全名称,其中安全名称是创建snmp指定user设置的new OctetString("SNMPV3"),针对snmpv1和snmpv2c需要设置团体名。另外必须设置ipAddress,且对应的主机要配置snmp否则获取不到值。如下:

  1. private static Target createTarget(int version, int port) {
  2. Target target = null;
  3. if (!(version == SnmpConstants.version3 || version == SnmpConstants.version2c || version == SnmpConstants.version1)) {
  4. log.error("参数version异常");
  5. return target;
  6. }
  7. if (version == SnmpConstants.version3) {
  8. target = new UserTarget();
  9. //snmpV3需要设置安全级别和安全名称,其中安全名称是创建snmp指定user设置的new OctetString("SNMPV3")
  10. target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
  11. target.setSecurityName(new OctetString("SNMPV3"));
  12. } else {
  13. //snmpV1和snmpV2需要指定团体名名称
  14. target = new CommunityTarget();
  15. ((CommunityTarget)target).setCommunity(new OctetString(community));
  16. if (version == SnmpConstants.version2c) {
  17. target.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
  18. }
  19. }
  20. target.setVersion(version);
  21. //必须指定,没有设置就会报错。
  22. target.setAddress(GenericAddress.parse(ipAddress+port));
  23. target.setRetries(5);
  24. target.setTimeout(3000);
  25. return target;
  26. }

  第三步:创建报文。其中要注意的是pdu可以设置类型,如果想要用snmpget方法,就设置PDU.GET.

  1. private static PDU createPDU(int version, int type, String oid){
  2. PDU pdu = null;
  3. if (version == SnmpConstants.version3) {
  4. pdu = new ScopedPDU();
  5. }else {
  6. pdu = new PDUv1();
  7. }
  8. pdu.setType(type);
  9. //可以添加多个变量oid
  10. pdu.add(new VariableBinding(new OID(oid)));
  11. return pdu;
  12. }

  最后一步发送报文也是最重要的一步,需要前面三步的支撑才能进行。如下:

  1. public static void snmpGet(String oid){
  2. try {
  3. //1、初始化snmp,并开启监听
  4. initSnmp();
  5. //2、创建目标对象
  6. Target target = createTarget(SnmpConstants.version2c, SnmpConstants.DEFAULT_COMMAND_RESPONDER_PORT);
  7. //3、创建报文
  8. PDU pdu = createPDU(SnmpConstants.version2c, PDU.GET, oid);
  9. System.out.println("-------> 发送PDU <-------");
  10. //4、发送报文,并获取返回结果
  11. ResponseEvent responseEvent = snmp.send(pdu, target);
  12. PDU response = responseEvent.getResponse();
  13. System.out.println("返回结果:" + response);
  14. }
  15. catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. }

  测试如下:

  1. public static void main(String[] args) {
  2. snmpGet("1.3.6.1.2.1.1.1.0");
  3. }

  output

  1. -------> 发送PDU <-------
  2. 返回结果:RESPONSE[requestID=1344419162, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.2.1.1.1.0 = Linux localhost.localdomain 3.10.0-327.36.2.el7.x86_64 #1 SMP Mon Oct 10 23:08:37 UTC 2016 x86_64]]

  从中可以得知,snmpget是可以根据指定的oid获取其对应的内容的。

  2、SNMPWalk功能测试

  查看了下PDU的源码,发现没有对应snmpwalk的类型,所以使用getNext类型来实现snmpwalk功能。
  

  1. public static void snmpWalk(String oid) {
  2. try {
  3. //1、初始化snmp,并开启监听
  4. initSnmp();
  5. //2、创建目标对象
  6. Target target = createTarget(SnmpConstants.version2c, SnmpConstants.DEFAULT_COMMAND_RESPONDER_PORT);
  7. //3、创建报文
  8. PDU pdu = createPDU(SnmpConstants.version2c, PDU.GETNEXT, oid);
  9. System.out.println("-------> 发送PDU <-------");
  10. //4、发送报文,并获取返回结果
  11. boolean matched = true;
  12. while (matched) {
  13. ResponseEvent responseEvent = snmp.send(pdu, target);
  14. if (responseEvent == null || responseEvent.getResponse() == null) {
  15. break;
  16. }
  17. PDU response = responseEvent.getResponse();
  18. String nextOid = null;
  19. Vector<? extends VariableBinding> variableBindings = response.getVariableBindings();
  20. for (int i = 0; i < variableBindings.size(); i++) {
  21. VariableBinding variableBinding = variableBindings.elementAt(i);
  22. Variable variable = variableBinding.getVariable();
  23. nextOid = variableBinding.getOid().toDottedString();
  24. //如果不是这个节点下的oid则终止遍历,否则会输出很多,直到整个遍历完。
  25. if (!nextOid.startsWith(oid)) {
  26. matched = false;
  27. break;
  28. }
  29. //System.out.println(variable);
  30. }
  31. if (!matched) {
  32. break;
  33. }
  34. pdu.clear();
  35. pdu.add(new VariableBinding(new OID(nextOid)));
  36. System.out.println("返回结果:" + response);
  37. }
  38. }
  39. catch (IOException e) {
  40. // TODO Auto-generated catch block
  41. e.printStackTrace();
  42. }
  43. }

  测试如下:

  1. public static void main(String[] args) {
  2. //snmpGet("1.3.6.1.2.1.1.1.0");
  3. snmpWalk("1.3.6.1.2.1.25.3.3.1.2");//CPU的当前负载,N个核就有N个负载 }
  1. -------> 发送PDU <-------

返回结果:RESPONSE[requestID=1014693266, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.2.1.25.3.3.1.2.196608 = 1]]
返回结果:RESPONSE[requestID=1014693268, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.2.1.25.3.3.1.2.196609 = 0]]

  用命令获取的结果是跟代码输出的结果是一样的,如下:

  3、前面两个案例都是跟采集有关,接下来介绍如何监控接收服务器发过来的故障然后提示个用户,这就需要用到snmptrap了。接下来我们直接看案例:

  处理流程:

  1、必须实现CommandResponder接口

  2、初始化snmp并开启监听。这步跟上面初始化一样,只是面对并发的情况使用MultiThreadedMessageDispatcher进行信息处理。

  3、将当前实现CommandResponder的对象添加至snmp的addCommandResponder才能接收到信息。

  4、处理接收到信息,通知用户。

  1. package com.yuanfy.study.snmp;
  2.  
  3. import java.io.IOException;
  4.  
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.snmp4j.CommandResponder;
  8. import org.snmp4j.CommandResponderEvent;
  9. import org.snmp4j.MessageDispatcher;
  10. import org.snmp4j.MessageDispatcherImpl;
  11. import org.snmp4j.PDU;
  12. import org.snmp4j.Snmp;
  13. import org.snmp4j.TransportMapping;
  14. import org.snmp4j.mp.MPv1;
  15. import org.snmp4j.mp.MPv2c;
  16. import org.snmp4j.mp.MPv3;
  17. import org.snmp4j.security.AuthSHA;
  18. import org.snmp4j.security.PrivAES128;
  19. import org.snmp4j.security.SecurityProtocols;
  20. import org.snmp4j.security.USM;
  21. import org.snmp4j.security.UsmUser;
  22. import org.snmp4j.smi.GenericAddress;
  23. import org.snmp4j.smi.OctetString;
  24. import org.snmp4j.smi.UdpAddress;
  25. import org.snmp4j.transport.DefaultUdpTransportMapping;
  26. import org.snmp4j.util.MultiThreadedMessageDispatcher;
  27. import org.snmp4j.util.ThreadPool;
  28.  
  29. public class SnmpTrapHandler implements CommandResponder{
  30. private static Logger log = LoggerFactory.getLogger(SnmpTrapHandler.class);
  31. private static int threadNum = 200;
  32. private static String ipAddress = "udp:10.10.112.177/162";
  33. private Snmp snmp = null;
  34. public void init(){
  35. //1、初始化多线程消息转发类
  36. ThreadPool threadPool = ThreadPool.create("SnmpTrap", threadNum);
  37. MessageDispatcher messageDispatcher = new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
  38. //其中要增加三种处理模型。如果snmp初始化使用的是Snmp(TransportMapping<? extends Address> transportMapping) ,就不需要增加
  39. messageDispatcher.addMessageProcessingModel(new MPv1());
  40. messageDispatcher.addMessageProcessingModel(new MPv2c());
  41. OctetString localEngineID = new OctetString(MPv3.createLocalEngineID());
  42. USM usm = new USM(SecurityProtocols.getInstance().addDefaultProtocols(), localEngineID, 0);
  43. UsmUser user = new UsmUser(new OctetString("SNMPV3"), AuthSHA.ID, new OctetString("authPassword"),
  44. PrivAES128.ID, new OctetString("privPassword"));
  45. usm.addUser(user.getSecurityName(), user);
  46. messageDispatcher.addMessageProcessingModel(new MPv3(usm));
  47. //2、创建transportMapping
  48. TransportMapping<?> transportMapping = null;
  49. try {
  50. UdpAddress updAddr = (UdpAddress) GenericAddress.parse(System.getProperty("snmp4j.listenAddress", ipAddress));
  51. transportMapping = new DefaultUdpTransportMapping(updAddr);
  52. //3、正式创建snmp
  53. snmp = new Snmp(messageDispatcher, transportMapping);
  54. //开启监听
  55. snmp.listen();
  56. } catch (IOException e) {
  57. log.error("初始化transportMapping失败:", e.getMessage());
  58. e.printStackTrace();
  59. }
  60. }
  61.  
  62. public void start() {
  63. init();
  64. //一定要将当前对象添加至commandResponderListeners中
  65. snmp.addCommandResponder(this);
  66. System.out.println("开始监听trap信息:");
  67. }
  68. /**
  69. * 处理信息方法
  70. */
  71. @Override
  72. public void processPdu(CommandResponderEvent event) {
  73. String version = null ;
  74. String community = null;
  75. if (event.getPDU().getType() == PDU.V1TRAP) {
  76. version = "v1";
  77. community = new String(event.getSecurityName());
  78. } else if (event.getPDU().getType() == PDU.TRAP){
  79. if (event.getSecurityModel() == 2) {
  80. version = "v2";
  81. community = new String(event.getSecurityName());
  82. }else {
  83. version = "v3";
  84. }
  85. }
  86. System.out.println("接收到的trap信息:[发送来源="+event.getPeerAddress()+",snmp版本="+version+",团体名="+community+", 携带的变量="+event.getPDU().getVariableBindings()+"]");
  87. }
  88. public static void main(String[] args) {
  89. SnmpTrapHandler handler = new SnmpTrapHandler();
  90. handler.start();
  91. }
  92. }

  测试如下:

  

  

基于Java使用Snmp4j进行监控与采集(snmptrap、snmpwalk、snmpget)的更多相关文章

  1. 基于Java visualvm的可视化监控的使用

    1 Java visualVM可视化监控工具打开方式 ctrl + r 快捷键调出运行窗口,输出 jvisualvm指令,即可打开java visualVM工具.详情如下图: 2 Java Visua ...

  2. 基于java spring框架开发部标1078视频监控平台精华文章索引

    部标1078视频监控平台,是一个庞杂的工程,涵盖了多层协议,部标jt808,jt809,jt1078,苏标Adas协议等,多个平台功能标准,部标796标准,部标1077标准和苏标主动安全标准,视频方面 ...

  3. 基于Java Agent的premain方式实现方法耗时监控(转),为了找到结论执行:premain在jvm启动的时候执行,所有方法前,会执行MyAgent的premain方法

    Java Agent是依附于java应用程序并能对其字节码做相关更改的一项技术,它也是一个Jar包,但并不能独立运行,有点像寄生虫的感觉.当今的许多开源工具尤其是监控和诊断工具,很多都是基于Java ...

  4. 【转载】 java利用snmp4j包来读取snmp协议数据(Manager端)

    https://www.cnblogs.com/xdp-gacl/p/4187089.html http://doc.okbase.net/yuanfy008/archive/265663.html ...

  5. 线程池的介绍和使用,以及基于jvmti设计非入侵监控

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 五常大米好吃! 哈哈哈,是不你总买五常大米,其实五常和榆树是挨着的,榆树大米也好吃, ...

  6. 基于Java Mina框架的部标808服务器设计和开发

    在开发部标GPS平台中,部标808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言. 我们为客户开发的部标服务器基于Min ...

  7. 基于Java的数据采集(终结篇)

    关于写过关于JAVA采集入库的三篇文章: 基于Java数据采集入库(一):http://www.cnblogs.com/lichenwei/p/3904715.html 基于Java数据采集入库(二) ...

  8. Spring IOC之基于JAVA的配置

    基础内容:@Bean 和 @Configuration 在Spring中新的支持java配置的核心组件是 @Configuration注解的类和@Bean注解的方法. @Bean注解被用于表明一个方法 ...

  9. [原创]Java应用性能远程监控系统(C/S架构)

    Java应用性能远程监控系统(使用C/S架构) 适用于监控所有Java应用,具有堆内存监控.方法区监控.GC监控.类加载监控.类编译监控与线程监控,提供堆快照下载,线程快照下载.体验网址:http:/ ...

随机推荐

  1. Linux分区规划与xshell使用排错

    1.1 没有重要数据 /boot   200M    存放系统的引导信息 内核 swap   交换分区   防止内存用光了 临时的一个内存 如果你的内存小于8G swap是内存的1.5倍   如果你的 ...

  2. PTA 循环单链表区间删除 (15 分)

    本题要求实现带头结点的循环单链表的创建和单链表的区间删除.L是一个带头结点的循环单链表,函数ListCreate_CL用于创建一个循环单链表,函数ListDelete_CL用于删除取值大于min小于m ...

  3. Postman参数化使用以及中文乱码问题解决

    1.参数化详解 准备工作,数据准备 2.使用csv文件时中文乱码可以通过使用txt文本,json文本改变调用json文件改变文件的编码格式解决 3:参数化数据调用的两种方式通过调用读取文件传入环境变量 ...

  4. java删除数组中的第n个数

    package test; import java.util.Scanner; public class Deletearr { public static void deletearr(){ Sca ...

  5. 原生js绑定和解绑事件,兼容IE,FF,chrome

    主要是最近项目中用到了原生的js 解绑和绑定 事件  然后今天研究了一下,其实问题不大,不过要注意不要把单词写错了,今天我就找了好久单词写错了. 需求:当鼠标移上去以后,给Select加载元素,接着解 ...

  6. 学会WCF之试错法——数据传输

    数据传输 服务契约 [ServiceContract] public interface IService { [OperationContract] string GetData(int value ...

  7. python基础(三)----字符编码以及文件处理

      字符编码与文件处理 一.字符编码 由字符翻译成二进制数字的过程   字符--------(翻译过程)------->数字   这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之 ...

  8. 【原创】使用workstation安装Xenserver 6.5+cloudstack 4.10----本地存储模式

    1. 背景: 近期由于项目和个人学习得需求,开始接触到Cloudstack,虽然云计算概念在大学刚毕业的时候就已经略有耳闻,但是由于工作原因,也一直没有了解,下班后想自己折腾下cloudstack,便 ...

  9. Git提交到github上

    1.本地创建一个目录redis [guosong@etch171 mars171 redis]# pwd /data1/guosong/code/redis [guosong@etch171 mars ...

  10. 关于 innodb_stats_on_metadata 的设置问题

    [问题背景] 线上使用osc进行表修改的时候出现SQL执行过长被kill的问题