OC通过SNMP上报告警出现中乱码

[复制链接]
发表于 : 2017-12-11 14:46:53 最新回复:2017-12-11 23:03:41
3240 1

1.1 上层网管收到OC通过SNMP上报的中文告警为乱码

产品

OperationCenter

版本

OC 2.X, 3.0.X

故障类型

对接故障

关键字

OSS网管 SNMP 告警上报 中文乱码

摘要

客户通过在OC上配置SNMP,通过SNMPOC上的告警上报到客户自己的网管系统中。

问题描述/现象描述

客户收到OC上报的告警,解析时对接收到的中文告警解析不出来,或者解析的告警为乱码。

告警信息

NA

处理过程

NA

根因

客户通过开源jarSNMP4j解析OC上报的告警时,由于告警携带的部分告警内容为中文的,并且snmp4j对中文字符解析存在问题,因此遇到中文时,解析出现问题。SNMP4J处理中文时的问题:当遇到中文或者编码值大于 0x80 的字符时,就会直接以十六机制数输出,因此客户端针对中文进行编码解析。

解决方案/操作步骤

     通过在百度上搜索snmp 中文乱码,可以搜索对应的问题解决帖子,写的比较详细的为下面这个帖子。

20171211144649015001.png

【转载】http://blog.chinaunix.net/uid-24948299-id-2538449.html帖子原文,。

SNMP4J 处理中文信息时的问题

首先说,多数时候你并不会遇到SNMP中文问题

多数网络设备和网管软件都是西文的.这个"多数"的意思是95%以上.
目前有可能遇到的中文SNMP问题的场景:
1.
一些国产网络设备(别提华为,华为路由器的多数网管信息也是西文的)
2. Windows
平台的SNMP服务
3.
一些国产网管软件
SNMP4J
处理中文时的问题:当遇到中文或者编码值大于 0x80 的字符时,就会直接以十六机制数输出

现象:

   Vector<VariableBinding> responseVB = respEvent.getResponse().getVariableBindings();
                     
   if(1==responseVB.size()){
     tempV = responseVB.elementAt(0);                                             
     System.out.println(tempV.getOid().toString()+":"+tempV.getVariable());
     System.out.println(tempV.getVariable().getSyntaxString());
                            }

执行代码:
1.3.6.1.2.1.2.2.1.2.1:4d:53:20:54:43:50:20:4c:6f:6f:70:62:61:63:6b:20:69:6e:74:65:72:66:61:63:65:00
OCTET STRING
1.3.6.1.2.1.2.2.1.2.2:56:4d:77:61:72:65:20:56:69:72:74:75:61:6c:20:45:74:68:65:72:6e:65:74:20:41:64:61:70:74:65:72:20:66:6f:72:20:56:4d:6e:65:74:38:00
OCTET STRING
1.3.6.1.2.1.2.2.1.2.3:56:4d:77:61:72:65:20:56:69:72:74:75:61:6c:20:45:74:68:65:72:6e:65:74:20:41:64:61:70:74:65:72:20:66:6f:72:20:56:4d:6e:65:74:31:00
OCTET STRING
1.3.6.1.2.1.2.2.1.2.4:52:65:61:6c:74:65:6b:20:52:54:4c:38:31:33:39:20:46:61:6d:69:6c:79:20:50:43:49:20:46:61:73:74:20:45:74:68:65:72:6e:65:74:20:4e:49:43:20:2d:20:ca:fd:be:dd:b0:fc:bc:c6:bb:ae:b3:cc:d0:f2:ce:a2:d0:cd:b6:cb:bf:da:00
OCTET STRING
1.3.6.1.2.1.2.2.1.2.65542:41:53:55:53:20:38:30:32:2e:31:31:62:2f:67:20:57:69:72:65:6c:65:73:73:20:4c:41:4e:20:43:61:72:64:20:2d:20:ca:fd:be:dd:b0:fc:bc:c6:bb:ae:b3:cc:d0:f2:ce:a2:d0:cd:b6:cb:bf:da:00
OCTET STRING   

·         原因:问题出在SNMP4J的基础字符串类OctetString上。

(SNMP4J体系下的字符串是以OctetString的形式而不是String形式存在和处理的。各种和字符串有关的资源如community,version,user,password等都是基于OctetString)
问题出在OctetString类的toString方法:

public class OctetString extends AbstractVariable
    implements AssignableFromByteArray, AssignableFromString {
  
    public String toString() {
        if (isPrintable()) {
          return new String(value);
        }
        return toHexString();
        // 没通过isPrintable()判断的,如ASCII控制字符,汉字等,都以16进制显示
      }

  public boolean isPrintable() {
    for (int i=0; i<value.length; i++) {
      char c = (char)value[i];
      if ((Character.isISOControl(c) ||
          ((value[i] & 0xFF) >= 0x80)) && (!Character.isWhitespace(c))) {
          // 判断其是否大于0x80 (即通常所说的大于128ASCII码,汉字编码都在这个区间内
        return false;
      }
    }
    return true;
  }




·         解决法1:网上有人给的建议是直接把OctetString类里toString方法里的if (isPrintable())部分取消掉,就是用基本的String转换

  public String toString() {
      return new String(value);

  }

测试:

1.3.6.1.2.1.2.2.1.2.1:MS TCP Loopback interface
OCTET STRING
1.3.6.1.2.1.2.2.1.2.2:VMware Virtual Ethernet Adapter for VMnet8
OCTET STRING
1.3.6.1.2.1.2.2.1.2.3:VMware Virtual Ethernet Adapter for VMnet1
OCTET STRING
1.3.6.1.2.1.2.2.1.2.4:Realtek RTL8139 Family PCI Fast Ethernet NIC - 数据包计划程序微型端口
OCTET STRING
1.3.6.1.2.1.2.2.1.2.65542:ASUS 802.11b/g Wireless LAN Card - 数据包计划程序微型端口
OCTET STRING


这种方法更不可取,因为isPrintable()方法是用于判断可显示字符的,其中不止判断大于0x80,还有包括控制字符的判断(0-31,127-159
codePoint >= 0x0000 && codePoint <= 0x001F) || (codePoint >= 0x007F && codePoint <= 0x009F);



·         解决法2:克服法1的缺陷,toString()不变,只修改isPrintable()

public String toString() {
        if (isPrintable()) {
          return new String(value);
        }
        return toHexString();
      }

  public boolean isPrintable() {
    for (int i=0; i<value.length; i++) {
      char c = (char)value[i];
      int codePoint =  (int)value[i];
      if (((codePoint > 0x0000 && codePoint <= 0x001F) ||
           (codePoint >= 0x007F && codePoint <= 0x009F)) && (!Character.isWhitespace(c))) {
        return false;
      }
    }
    return true;
  }

   
注意:上面codePoint变量的操作,基本就是Character.isISOControl(c)的操作
   
windows 平台的snmp信息会以‘\0'结尾,这样windows平台任何snmp信息都通不过Character.isISOControl(c)的判断
  
所以必须把Character.isISOControl(c)中的codePoint >= 0x0000改成codePoint > 0x0000



·         解决法3:在国外的论坛上,有的比较死板的人要求按正规的“继承+覆写方法”的方式做修改,这样能保证源码的不被改变

其实仔细想想,完全不修改源码是很难的,所谓“牵一发而动全身”。
既然是开源的代码,该修改就修改

 

建议与总结

NA

附件

NA

 

  • x
  • 常规:

点评 回复

跳转到指定楼层
建赟
建赟  专家 发表于 2017-12-11 23:03:41 已赞(0) 赞(0)

感谢分享
  • x
  • 常规:

点评 回复

发表回复
您需要登录后才可以回帖 登录 | 注册

警告 内容安全提示:尊敬的用户您好,为了保障您、社区及第三方的合法权益,请勿发布可能给各方带来法律风险的内容,包括但不限于政治敏感内容,涉黄赌毒内容,泄露、侵犯他人商业秘密的内容,侵犯他人商标、版本、专利等知识产权的内容,侵犯个人隐私的内容等。也请勿向他人共享您的账号及密码,通过您的账号执行的所有操作,将视同您本人的行为,由您本人承担操作后果。详情请参看“隐私声明
如果附件按钮无法使用,请将Adobe Flash Player 更新到最新版本!
登录参与交流分享

登录参与交流分享

登录