golang snmp开发学习笔记(二)

来源:互联网 时间:1970-01-01

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 mainimport ( "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 mainimport ( "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.MaxRepetitionsif 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 mainimport ( "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操作。



相关阅读:
Top