【问题标题】:How do you pass TCP connection objects to other Go modules?你如何将 TCP 连接对象传递给其他 Go 模块?
【发布时间】: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 已经是一个接口。这种恐慌应该伴随着一些指向导致它的确切行的回溯。我想知道它是否发生在解码器调用中,如果它发生在您尝试取消引用解码器的解码方法时
  • 我现在添加了回溯,但仍然无法理解它。

标签: map tcp go gob


【解决方案1】:

更新:发现问题!我没有意识到你可以 fmt.Println(conn) 从中获取更多信息,并发现 conn 为 nil,这引起了恐慌。很抱歉给您带来麻烦,感谢您的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 2016-10-15
    • 1970-01-01
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    相关资源
    最近更新 更多