golang snmp开发学习笔记(二)

wbchen2330 · · 6108 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

  soniah/gosnmp是一个纯go语言编写的SNMP包,基于alouca/gosnmp开发。目前提供GetRequest、GetNext、GetBulk、Walk和SetRequest功能,支持IPv4和IPv6, 支持SNMPv2c和SNMPv3。
  本文介绍soniah/gosnmp的SetRequest和Walk操作。

SetRequest

  snoiah/gosnmp的GoSNMP.Set()方法有一个明显的错误:

func (x *GoSNMP) Set(pdus []SnmpPDU) (result *SnmpPacket, err error) {
    if pdus[0].Type != Integer || pdus[0].Type != OctetString {
        return nil, fmt.Errorf("ERR:gosnmp currently only supports SNMP SETs for Integers and OctetStrings")
    }
    // build up SnmpPacket
    packetOut := x.mkSnmpPacket(SetRequest, 0, 0)
    return x.send(pdus, packetOut)
}

  if语句的两个条件应该是“与”的关系,亦即若PDU的类型既不是Integer也不是OctetString则报错(soniah/gosnmp目前Set操作只支持Integer和OctetString两种类型),因此||应改为&&

set_request.go

package main

import (
    "fmt"
    "log"
    "time"
    g "github.com/soniah/gosnmp"
)

func main() {
    var pdus []gs.SnmpPDU
    pdu := gs.SnmpPDU {
        Name: "1.3.6.1.2.1.1.5.0",
        Type: gs.OctetString,
        Value: "new_name",
    }
    pdus = append(pdus, pdu)

    g.Default.Target = "172.18.0.2"
    g.Default.Community = "community"
    err := gs.Default.Connect()
    if err != nil {
        fmt.Printf("Connect() err: %v\n", err)
    }
    defer g.Default.Conn.Close()

    result, err := g.Default.Set(pdus)
    if err != nil {
        fmt.Printf("Set() err: %v", err)
    }
    for i, v := range result.Variables {
        fmt.Printf("%d. oid: %s ", i, v.Name)
        switch v.Type {
        case g.OctetString:
            fmt.Printf("string: %s\n", string(v.Value.([]byte)))
        default:
            fmt.Printf("number: %d\n", g.ToBigInt(v.Value))
        }
    }
}

Walk

  Walk不是SNMP的原语,是利用GetNext或GetBulk等操作构建的快捷工具,一般用于一次性获取一棵子树的管理对象,也可用于遍历整个MIB树(注意有些设备厂商为了不让第三方获取完整的MIB,会故意将私有MIB设置成不连续,Walk操作将会在不连续处终止。强烈鄙视这些厂商)。

walk.go

package main

import (
    "fmt" 
    g "github.com/soniah/gosnmp"
)

func main() {
    g.Default.Target = "172.18.0.2"
    g.Default.Community = "community"
    err :=g.Default.Connect()
    if err != nil {
        fmt.Printf("Connect() err: %v", err)
    }
    defer g.Default.Conn.Close()

    oid := ".1.3.6.1.2.1.2.2.1.2"
    //定义回调函数,每个GetNext操作完成后用来处理返回的SnmpPDU
    //函数类型:type WalkFunc func(dataUnit SnmpPDU) error
    fn := func(v g.SnmpPDU) error {
        fmt.Printf("oid: %s, value: ", v.Name)
        switch v.Type{
        case g.OctetString:
            fmt.Printf("%s\n", string(v.Value.([]byte)))
        default:
            fmt.Printf("%d\n", g.ToBigInt(v.Value))
        }
        return nil
    }
    err = g.Default.Walk(oid, fn)
    if err != nil {
        fmt.Printf("Walk() err: %v", err)
    }
}

  GoSNMP.Wall()方法使用GetNext操作实现,每个oid需要执行一次GetNext(),效率较低,可以使用BulkWall()方法加以改进,BulkWalk()使用GetBulk操作,一次返回多个oid。
  源码中Walk和BulkWalk使用相同的函数,只有一个区别:

maxReps := x.MaxRepetitions
if maxReps <= 0 {
    maxReps = defaultMaxRepetitions
}

getFn := func(oid string) (result *SnmpPacket, err error) {
    switch getRequestType {
    case GetBulkRequest:
        return x.GetBulk([]string{oid}, uint8(x.NonRepeaters), uint8(maxReps))
    case GetNextRequest:
        return x.GetNext([]string{oid})
    default:
        return nil, fmt.Errorf("Unsupported request type: %d", getRequestType)
    }
}

  BulkWalk()Walk()的使用方法一样,只需把walk.go代码的g.Default.Walk(oid)换成g.Default.BulkWalk(oid),效果一样,只是使用了更为高效的GetBulk操作。

WalkAll

  GoSNMP.Walk()方法采用回调函数处理返回的数据,WalkAll()方法提供了常规的处理方式,将每个操作返回的PDU存储在一个数组里,遍历操作结束后返回给调用者处理。
walk_all.go

package main

import (
    "fmt" 
    g "github.com/soniah/gosnmp"
)

func main() {
    g.Default.Target = "172.18.0.2"
    g.Default.Community = "community"
    err :=g.Default.Connect()
    if err != nil {
        fmt.Printf("Connect() err: %v", err)
    }
    defer g.Default.Conn.Close()

    oid := ".1.3.6.1.2.1.2.2.1.2"

    result, err := g.Default.WalkAll(oid)
    if err != nil {
        fmt.Printf("Walk() err: %v", err)
    }

    for _, v := range result {
        fmt.Printf("oid: %s, value: ", v.Name)
        switch v.Type{
        case g.OctetString:
            fmt.Printf("%s\n", string(v.Value.([]byte)))
        default:
            fmt.Printf("%d\n", g.ToBigInt(v.Value))
        }
    }
}

  BulkWalkAll()WalkAll()的使用方法一样,只需把walk_all.go代码中的g.Default.WalkAll(oid)换成g.Default.BulkWalkAll(oid),效果一样,只是使用了更为高效的GetBulk操作。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:wbchen2330

查看原文:golang snmp开发学习笔记(二)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

6108 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传