這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
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操作。