【发布时间】:2014-04-26 10:14:44
【问题描述】:
我有一个主机名到连接的映射,我试图将这些映射传递给我正在用 Go 编写的应用程序的不同模块。
var conns_ map[string]net.Conn // tcp connections per node
在主 server.go 文件中,我拨打网络中的其他服务器并将连接保存到此地图:
conn, err := net.Dial("tcp", address)
conns_[hostname] = conn
然后我想将此地图发送到其他模块以重新使用连接。这是我如何将其发送到学习器模块的示例:
go learner.ListenForNotifies(conns_, selfname_)
在学习器模块中,我获取地图并开始尝试在它包含的每个连接上使用 gob.Decoder:
func ListenForNotifies(conns map[string]net.Conn, selfname string) {
for hostname, conn := range conns {
go listen(hostname, conn, lChan)
}
// etc.
}
在监听函数内:
func listen(hostname string, conn net.Conn, lChan chan string) {
decoder := gob.NewDecoder(conn)
proposal := &utils.Proposal{}
err := decoder.Decode(proposal)
// etc.
}
问题是当我在这里调用 decoder.Decode(proposal) 时,会发生恐慌:
panic: runtime error: invalid memory address or nil pointer dereference
我在其他地方使用相同的编码/解码代码没有问题,唯一的区别是我尝试重用连接,而不是在同一函数中建立新连接后立即调用解码。我一直试图让这项工作好几个小时,尝试通过引用传递东西,使用 map[string]interface{},以及各种没有运气的事情。 Gob.decode 应该阻塞,直到在底层 net.Conn 对象上编码某些内容,对吗?我只能猜测 net.Conn 对象在这一点上已经以某种方式失效了。
我在传递连接对象的方式上做错了吗?我读到 net.Conn 是一个非常简单的对象,可以按值传递,但我一定遗漏了一些东西。尝试使用类型 interface{} 通过引用传递它时,出现如下错误:
interface {} does not implement net.Conn (missing Close method)
我现在不知所措,试图找出连接对象可能有什么问题,如果我误用 gob.Decode,将 net.Conn 对象放入地图中存在问题,或者问题是完全不同的东西。
有什么想法吗?
编辑:完整的恐慌回溯如下:
goroutine 16 [running]:
runtime.panic(0x527040, 0x6afe68)
/usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
bufio.(*Reader).fill(0xc21004a180)
/usr/local/go/src/pkg/bufio/bufio.go:91 +0x10a
bufio.(*Reader).Read(0xc21004a180, 0xc21000aa30, 0x1, 0x9, 0x1, ...)
/usr/local/go/src/pkg/bufio/bufio.go:159 +0x1a4
io.ReadAtLeast(0x7f2e22e8a360, 0xc21004a180, 0xc21000aa30, 0x1, 0x9, ...)
/usr/local/go/src/pkg/io/io.go:288 +0xf6
io.ReadFull(0x7f2e22e8a360, 0xc21004a180, 0xc21000aa30, 0x1, 0x9, ...)
/usr/local/go/src/pkg/io/io.go:306 +0x71
encoding/gob.decodeUintReader(0x7f2e22e8a360, 0xc21004a180, 0xc21000aa30, 0x9, 0x9, ...)
/usr/local/go/src/pkg/encoding/gob/decode.go:66 +0x98
encoding/gob.(*Decoder).recvMessage(0xc210069000, 0x0)
/usr/local/go/src/pkg/encoding/gob/decoder.go:73 +0x57
encoding/gob.(*Decoder).decodeTypeSequence(0xc210069000, 0xc210045f00, 0x160)
/usr/local/go/src/pkg/encoding/gob/decoder.go:159 +0x49
encoding/gob.(*Decoder).DecodeValue(0xc210069000, 0x4ea300, 0xc210045f60, 0x160, 0x0, ...)
/usr/local/go/src/pkg/encoding/gob/decoder.go:223 +0x12e
encoding/gob.(*Decoder).Decode(0xc210069000, 0x4ea300, 0xc210045f60, 0xb, 0x0)
/usr/local/go/src/pkg/encoding/gob/decoder.go:202 +0x1c5
group10/lab5/learner.listen(0x565f90, 0x12, 0x0, 0x0, 0xc21004a120)
/home/dev/go/src/learner/learner.go:51 +0x163
created by group10/lab5/learner.ListenForNotifies
/home/dev/go/src/learner/learner.go:26 +0x18a
更新:发现问题!我没有意识到你可以 fmt.Println(conn) 从中获取更多信息,并发现 conn 为 nil,这引起了恐慌。很抱歉给您带来麻烦,感谢您的帮助。
【问题讨论】:
-
原则上,将连接放在这样的地图中是可以的。但是它们有可能在打开它们和阅读它们之间的某个地方被关闭。您确定连接已正确建立吗?我也不确定那种恐慌。它究竟发生在哪里?
-
它恰好发生在
err := decoder.Decode(proposal)通话中。我确保连接对象在拨号时没有抛出错误,因此应该正确建立它。我故意没有在创建它的位置添加defer conn.Close(),以避免它提前关闭。 -
net.Conn 已经是一个接口。这种恐慌应该伴随着一些指向导致它的确切行的回溯。我想知道它是否发生在解码器调用中,如果它发生在您尝试取消引用解码器的解码方法时
-
我现在添加了回溯,但仍然无法理解它。