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操作。
有疑问加站长微信联系(非本文作者)