当结构体中包含嵌套结构体时,Golang的RPC调用可能不会返回。

huangapple go评论81阅读模式
英文:

golang rpc not returning when struct has a nested struct

问题

更新

从gob编码转换为json修复了问题。但是我仍然想知道为什么使用gob时会失败。

所以我的客户端代码看起来像这样:

account := new(database.Account)

err := client.Call("AccountDb.FindAccount", "username", account)

if err != nil {
	logger.FATAL.Print(err.Error())
	return
}

logger.INFO.Print(account)

在服务器端,AccountDb.FindAccount看起来像这样:

func (t *AccountDb) FindAccount(args *string, reply *Account) error {

	reply.Username = "this is a test"

	return nil
}

Account的结构如下:

type Account struct {
	Id           int
	Username     string
	Password     string
	Email        string
	Created      time.Time
	LastLoggedIn time.Time
	AccessLevel  int

	Banned struct {
		reason  string
		expires time.Time
	}
}

如果我尝试执行rpc请求,请求开始并且服务器执行该过程。然而,程序随后挂起,该过程不返回!但是,如果我从Account结构中删除Banned匿名结构,它就可以正常工作!为什么会这样?有解决这个问题的方法吗?

编辑
客户端和服务器注册代码如下:

客户端

client, err = rpc.DialHTTP("tcp", "127.0.0.1:9001")

if err != nil {
	logger.FATAL.Panic(err.Error())
}

服务器

defer db.Close()

account := new(database.AccountDb)
account.Database = db

rpc.Register(account)
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":9001")

if e != nil {
	logger.FATAL.Fatal("listen error:", e)
}
http.Serve(l, nil)
英文:

UPDATE

moving from gob encoding to json fixed the issue. However I would still like to know why this was failing to work with gob.

so my client code looks like this

account := new(database.Account)

err := client.Call("AccountDb.FindAccount", "username", account)

if err != nil {
	logger.FATAL.Print(err.Error())
	return
}

logger.INFO.Print(account)

On the server side AccountDb.FindAccount looks like this

func (t *AccountDb) FindAccount(args *string, reply *Account) error {

	reply.Username = "this is a test"

	return nil
}

The struct for Account looks like this

type Account struct {
	Id           int
	Username     string
	Password     string
	Email        string
	Created      time.Time
	LastLoggedIn time.Time
	AccessLevel  int

	Banned struct {
		reason  string
		expires time.Time
	}
}

if I attempt to perform the rpc the requests starts and the server executes the procedure. However the program then hangs and the procedure does not return! If however I remove the Banned anonymous struct from the Account struct it works fine! Why is this? is there a solution to this problem?

edit
the client and server register code looks like this

Client

client, err = rpc.DialHTTP("tcp", "127.0.0.1:9001")

if err != nil {
	logger.FATAL.Panic(err.Error())
}

Server

defer db.Close()

account := new(database.AccountDb)
account.Database = db

rpc.Register(account)
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":9001")

if e != nil {
	logger.FATAL.Fatal("listen error:", e)
}
http.Serve(l, nil)

答案1

得分: 6

显然,gob编码器无法对RPC响应进行编组,因为Banned结构体没有导出的字段。这个playground示例展示了这个错误:

encode error: gob: type struct { reason string; expires time.Time } 
has no exported fields

如果通过将reason/expires字段大写来导出它们,gob的往返操作就可以正常工作(参见http://play.golang.org/p/YrYFsk6trQ)。

JSON编码器也要求序列化字段被导出,但如果一个结构体没有导出字段,它不会返回错误。解码只会返回默认/零值。运行http://play.golang.org/p/OBBkB4tPcZ并注意在往返操作中Banned信息丢失了。

如果你需要在rpc包中检测这些类型的错误,有两个选项:

  1. 编辑rpc/debug.go,将logDebug标志设置为true,并重新构建rpc包,或者
  2. 实现一个包装现有实现的ServerCodec,并记录ReadRequestBody/WriteResponse返回的任何错误。
英文:

Evidently, the gob encoder fails to marshal the RPC response because the Banned struct has no exported fields. This playground example exhibits the error:

encode error: gob: type struct { reason string; expires time.Time } 
has no exported fields

If you export the reason/expires fields by capitalizing them, the gob round-trip works OK (see http://play.golang.org/p/YrYFsk6trQ).

The JSON encoder also requires that serialized fields are exported, but it does not return an error if a struct has none. The decode just returns default/zero values. Run http://play.golang.org/p/OBBkB4tPcZ and note that the Banned information is lost on the round-trip.

If you need to detect these kinds of errors in the rpc package, there are two options:

  1. Edit rpc/debug.go, set the logDebug flag to true, and rebuild the rpc package, or
  2. Implement a ServerCodec that wraps the existing implementation and logs any errors returned by ReadRequestBody/WriteResponse.

huangapple
  • 本文由 发表于 2014年6月10日 23:32:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/24145058.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定