更新
从 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)
最佳答案
显然,gob 编码器无法编码 RPC 响应,因为 Banned
结构没有导出字段。这playground example显示错误:
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
包中的此类错误,有两种选择:
- 编辑 rpc/debug.go ,将
logDebug
标志设置为true,并重建rpc
包,或者 - 实现一个
ServerCodec
,包装现有实现并记录ReadRequestBody
/WriteResponse
返回的任何错误。
关于当结构具有嵌套结构时,golang rpc 不返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24145058/