Golang中DBus的使用问题求助
Golang中DBus的使用问题求助 大家好,
首先声明我是Go语言的完全新手。目前我正在尝试创建一个API,通过dbus与远程KMIP服务器通信(这部分功能已经实现)。遗憾的是,除了godbus本身的文档外,找不到其他不包含大量(对我的应用来说不必要的)基础设施或将代码抽象到失去学习价值的示例资源。
我确信这里忽略了一些简单的细节。
我的服务器应用:
package main
import (
"log"
"github.com/godbus/dbus"
"github.com/godbus/dbus/introspect"
"local-gitlab.com/gkbassf/go-pykmip-wrapper/kmipcreatekeypair"
"local-gitlab.com/gkbassf/go-pykmip-wrapper/readconfigs"
)
const configfile = "/etc/ndvm/config/kmip-interpreter.conf"
// Server 是服务器对象,目前设置为0且未实际使用
type Server struct {
id uint32
}
func (s Server) servercreatekeypair(ca string, size uint32, opn string, pubname string, pubusage string, priname string, priusage string, debug bool, expireTimeout int32) (output string, dbuserr *dbus.Error) {
var Kpps kmipcreatekeypair.KeyPairParams
// 从输入参数填充结构
Kpps.Gca = ca
Kpps.Gsize = size
Kpps.Gopn = opn
Kpps.Gpubname = pubname
Kpps.Gpubuse.Set(pubusage)
Kpps.Gpriname = priname
Kpps.Gpriuse.Set(priusage)
Kpps.Gdebug = debug
out, err := kmipcreatekeypair.CreateKeyPair(Kpps)
if err != nil {
log.Fatal(err)
}
// dbuserr = err.(dbus.Error)
return out, dbuserr
}
func main() {
cfg, err := readconfigs.ReadConfig(configfile)
conn, err := dbus.SystemBus()
if err != nil {
panic(err)
}
reply, err := conn.RequestName(cfg.Bus.Iface, dbus.NameFlagDoNotQueue)
if err != nil {
panic(err)
}
if reply != dbus.RequestNameReplyPrimaryOwner {
panic("名称已被占用")
}
ckpNode := `
<node>
<interface name="` + cfg.Bus.Iface + `">
<method name="servercreatekeypair">
<arg direction="in" type="v"/>
<arg direction="out" type="s"/>
</method>
</interface>` + introspect.IntrospectDataString + `</node> `
s := Server{id: 0}
// 宣告服务开始运行
conn.Export(s, dbus.ObjectPath(cfg.Bus.Path), cfg.Bus.Iface)
// 为CreateKeyPair服务导出内省信息
conn.Export(introspect.Introspectable(ckpNode), dbus.ObjectPath(cfg.Bus.Path), "org.freedesktop.DBus.Introspectable")
// 注册方法
conn.ExportSubtree(s, dbus.ObjectPath(cfg.Bus.Path), cfg.Bus.Iface)
select {}
}
我的客户端应用:
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/godbus/dbus"
"github.com/godbus/dbus/introspect"
"local-gitlab.com/gkbassf/go-pykmip-wrapper/readconfigs"
)
const configfile = "/etc/ndvm/config/kmip-interpreter.conf"
var list []string
func main() {
cfg, err := readconfigs.ReadConfig(configfile)
conn, err := dbus.SystemBus()
if err != nil {
panic(err)
}
fmt.Println("已连接DBus...")
// 由于我们只是客户端,应该只能看到类似浮点数的内容
allOnBus := conn.Names()
for _, name := range allOnBus {
fmt.Println("返回: " + name)
}
// 检查远程接口
fmt.Println("对 " + cfg.Bus.Iface + " 进行内省调用")
node, err := introspect.Call(conn.Object(cfg.Bus.Iface, dbus.ObjectPath(cfg.Bus.Path)))
if err != nil {
panic(err)
}
fmt.Println("XML名称: " + (node.XMLName.Local))
fmt.Println("名称: " + node.Name)
for _, inf := range node.Interfaces {
fmt.Println(inf)
}
for _, child := range node.Children {
fmt.Println(child)
}
data, _ := json.MarshalIndent(node, "", " ")
os.Stdout.Write(data)
// 在打印结构后添加回车符
fmt.Println("")
// 设置预设调用
method := cfg.Bus.Iface + `.servercreatekeypair`
fmt.Println("调用方法 " + method)
err = conn.BusObject().Call(method, 0, `RSA`, 2048, `default`, `test15_RSA_Public_Key`, `VERIFY|DECRYPT`, `test15_RSA_Private_Key`, `SIGN`, false).Store(&list)
if err != nil {
panic(err)
}
for _, v := range list {
fmt.Println(v)
}
}
最终得到的结果(输出最后部分)… panic: org.freedesktop.DBus 无法理解 servercreatekeypair 消息
goroutine 1 [running]:
main.main()
/home/kbassford/go/src/local-gitlab.com/gkbassf/go-pykmip-wrapper/test/testdbusclient/testdbusclient.go:76 +0xd1a
所以我在思考为什么内省将"servercreatekeypair"列为有效方法,但在调用时却无法理解?是否忘记导出某些内容?提前感谢。
更多关于Golang中DBus的使用问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html
为后人记录解决方案,希望能帮助到其他人。
注意:我从这里得到了需要的提示:https://github.com/hoffoo/spotify-ctrl/blob/master/spotify.go
你需要连接到接口/路径下指定的特定DBus对象!(注意新的 func connDbus 函数。)这在dbus示例中没有明确说明。以下是修订后的客户端应用程序(同时包含增量日志改进)。
我的客户端应用程序
package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"time"
"github.com/godbus/dbus"
"github.com/godbus/dbus/introspect"
"local-gitlab.com/gkbassf/go-pykmip-wrapper/readconfigs"
)
const configfile = "/etc/ndvm/config/kmip-interpreter.conf"
var list []string
func connDbus(Iface string, ObjPath dbus.ObjectPath) *dbus.Object {
conn, err := dbus.SystemBus()
if err != nil {
log.Panic("ERROR: ", err)
}
return conn.Object(Iface, ObjPath).(*dbus.Object)
}
func main() {
var pdbus *dbus.Object
// 读取配置。
cfg, err := readconfigs.ReadConfig(configfile)
IFace := cfg.Bus.Iface
Opath := dbus.ObjectPath(cfg.Bus.Path)
pdbus = connDbus(IFace, Opath)
fmt.Println("Joined DBus ...")
// 由于我们只是客户端,应该只看到类似浮点数的内容。
// allOnBus := conn.Names()
// for _, name := range allOnBus {
// fmt.Println("Returned: " + name)
// }
// 检查远程接口。
fmt.Println("Call introspection on " + cfg.Bus.Iface)
node, err := introspect.Call(pdbus)
if err != nil {
panic(err)
}
fmt.Println("XMLNAME: " + (node.XMLName.Local))
fmt.Println("NAME: " + node.Name)
for _, inf := range node.Interfaces {
fmt.Println("INTERFACES: ", inf)
}
for _, child := range node.Children {
fmt.Println("CHILDREN: ", child)
}
data, err := json.MarshalIndent(node, "", " ")
if err == nil {
fmt.Println(string(data))
fmt.Println("")
} else {
fmt.Println("introspection failed ", err)
}
// 在打印结构后添加回车。
fmt.Println("")
rand.Seed(time.Now().UnixNano())
suid := fmt.Sprintf("%d", rand.Intn(99999))
// 设置预设调用。
method := `server_create_keypair`
fmt.Println("Calling method: ", method)
// kwargs := make(map[string]interface{})
kwargs := make(map[string]string)
kwargs["ca"] = "RSA"
kwargs["size"] = "2048"
kwargs["opn"] = "default"
kwargs["pubname"] = suid + "_RSA_Public_Key"
kwargs["pubusage"] = "VERIFY|DECRYPT"
kwargs["priname"] = suid + "_RSA_Private_Key"
kwargs["priusage"] = "SIGN"
kwargs["debug"] = "true"
fmt.Println("kwargs: ", kwargs)
paramlines, err := json.MarshalIndent(kwargs, "", " ")
if err == nil {
fmt.Println(string(paramlines))
fmt.Println("")
} else {
fmt.Println("cannot print parameters ", err)
}
err = pdbus.Call(method, 0, kwargs).Store(&list)
if err != nil {
log.Println(err)
}
for _, v := range list {
log.Println(v)
}
}
更多关于Golang中DBus的使用问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题在于客户端调用方法时使用了错误的对象路径和方法签名。在DBus中,方法调用需要指定正确的接口、对象路径和方法名。以下是修正后的客户端代码:
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/godbus/dbus"
"github.com/godbus/dbus/introspect"
"local-gitlab.com/gkbassf/go-pykmip-wrapper/readconfigs"
)
const configfile = "/etc/ndvm/config/kmip-interpreter.conf"
func main() {
cfg, err := readconfigs.ReadConfig(configfile)
if err != nil {
panic(err)
}
conn, err := dbus.SystemBus()
if err != nil {
panic(err)
}
fmt.Println("已连接DBus...")
// 检查总线上的名称
allOnBus := conn.Names()
for _, name := range allOnBus {
fmt.Println("总线上的名称: " + name)
}
// 内省调用
fmt.Println("对 " + cfg.Bus.Iface + " 进行内省调用")
node, err := introspect.Call(conn.Object(cfg.Bus.Iface, dbus.ObjectPath(cfg.Bus.Path)))
if err != nil {
panic(err)
}
fmt.Println("XML名称: " + (node.XMLName.Local))
fmt.Println("名称: " + node.Name)
for _, inf := range node.Interfaces {
fmt.Printf("接口: %s\n", inf.Name)
for _, method := range inf.Methods {
fmt.Printf(" 方法: %s\n", method.Name)
for _, arg := range method.Args {
fmt.Printf(" 参数: %s %s\n", arg.Direction, arg.Type)
}
}
}
data, _ := json.MarshalIndent(node, "", " ")
os.Stdout.Write(data)
fmt.Println("")
// 正确的方法调用方式
obj := conn.Object(cfg.Bus.Iface, dbus.ObjectPath(cfg.Bus.Path))
// 根据服务器端方法签名调整参数
var result string
err = obj.Call(cfg.Bus.Iface+".servercreatekeypair", 0,
"RSA", // ca string
uint32(2048), // size uint32
"default", // opn string
"test15_RSA_Public_Key", // pubname string
"VERIFY|DECRYPT", // pubusage string
"test15_RSA_Private_Key", // priname string
"SIGN", // priusage string
false, // debug bool
int32(0)).Store(&result) // expireTimeout int32
if err != nil {
panic(err)
}
fmt.Printf("调用结果: %s\n", result)
}
服务器端也需要修正内省XML中的方法签名:
ckpNode := `
<node>
<interface name="` + cfg.Bus.Iface + `">
<method name="servercreatekeypair">
<arg direction="in" type="s" name="ca"/>
<arg direction="in" type="u" name="size"/>
<arg direction="in" type="s" name="opn"/>
<arg direction="in" type="s" name="pubname"/>
<arg direction="in" type="s" name="pubusage"/>
<arg direction="in" type="s" name="priname"/>
<arg direction="in" type="s" name="priusage"/>
<arg direction="in" type="b" name="debug"/>
<arg direction="in" type="i" name="expireTimeout"/>
<arg direction="out" type="s" name="output"/>
</method>
</interface>` + introspect.IntrospectDataString + `</node> `
主要问题:
- 客户端使用了
conn.BusObject().Call()而不是通过具体的对象调用 - 方法参数类型不匹配 - 需要明确指定参数类型(string, uint32, bool, int32)
- 内省XML中缺少完整的参数定义
修正后的代码应该能正常工作。

