英文:
How do you pass TCP connection objects to other Go modules?
问题
我有一个主机名到连接的映射,我正在尝试将其传递给不同模块的应用程序中。以下是我在Go中编写的应用程序的一部分代码:
var conns_ map[string]net.Conn // 每个节点的TCP连接
在主服务器文件server.go中,我拨号到网络中的其他服务器,并将连接保存到这个映射中:
conn, err := net.Dial("tcp", address)
conns_[hostname] = conn
然后,我想将这个映射发送给其他模块以重用这些连接。以下是将其发送给learner模块的示例:
go learner.ListenForNotifies(conns_, selfname_)
在learner模块中,我接收这个映射,并尝试对其中包含的每个连接使用gob.Decoder:
func ListenForNotifies(conns map[string]net.Conn, selfname string) {
for hostname, conn := range conns {
go listen(hostname, conn, lChan)
}
// 其他操作
}
在listen函数中:
func listen(hostname string, conn net.Conn, lChan chan string) {
decoder := gob.NewDecoder(conn)
proposal := &utils.Proposal{}
err := decoder.Decode(proposal)
// 其他操作
}
问题是,当我在这里调用decoder.Decode(proposal)时,会发生panic:
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对象放入映射中存在问题,或者问题完全不同。
有什么想法吗?
编辑:完整的panic回溯如下:
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,这导致了panic。对此给你带来的麻烦表示抱歉,感谢你的帮助。
<details>
<summary>英文:</summary>
I have a map of hostnames to connections that I am trying to pass around to different modules for an application that I am writing in Go.
var conns_ map[string]net.Conn // tcp connections per node
In the main server.go file, I dial the other servers in my network and save the connections to this map:
conn, err := net.Dial("tcp", address)
conns_[hostname] = conn
Then I want to send this map to other modules to re-use the connections. Here is an example for how I send it to the learner module:
go learner.ListenForNotifies(conns_, selfname_)
In the learner module I take the map and start trying to use a gob.Decoder on each connection that it contains:
func ListenForNotifies(conns map[string]net.Conn, selfname string) {
for hostname, conn := range conns {
go listen(hostname, conn, lChan)
}
// etc.
}
And within the listen function:
func listen(hostname string, conn net.Conn, lChan chan string) {
decoder := gob.NewDecoder(conn)
proposal := &utils.Proposal{}
err := decoder.Decode(proposal)
// etc.
}
The problem is that when I call decoder.Decode(proposal) here, a panic happens:
panic: runtime error: invalid memory address or nil pointer dereference
I use this same encode/decode code elsewhere without problems, and the only difference is that I'm trying to re-use a connection instead of calling decode immediately after establishing a new one within the same function. I've been trying to make this work for hours, trying to pass things by reference, using map[string]interface{}, and all sorts of things without luck. Gob.decode should block until something is encoded on the underlying net.Conn object, right? I can only guess that the net.Conn object has gotten invalidated somehow by this point.
Am I doing something wrong with how I am passing around connection objects? I read that a net.Conn was a very simple object that was fine to pass by value, but I must be missing something. When attempting to pass it by reference using type interface{}, I got errors like:
interface {} does not implement net.Conn (missing Close method)
I'm at a loss now, trying to figure out what could be wrong with the connection objects, if I'm misusing gob.Decode, there's an issue with putting net.Conn objects into maps, or if the problem is something completely different.
Any ideas?
edit: The full panic traceback is below:
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
Update: The problem was found! I didn't realize that you could just fmt.Println(conn) to get more information out of it, and discovered that the conn was nil, and that caused the panic. Sorry for the trouble, and thanks for your help.
</details>
# 答案1
**得分**: 1
更新:问题已找到!我没有意识到可以使用fmt.Println(conn)来获取更多信息,发现conn是空的,这导致了恐慌。对于给你带来的麻烦,我表示抱歉,并感谢你的帮助。
<details>
<summary>英文:</summary>
Update: The problem was found! I didn't realize that you could just fmt.Println(conn) to get more information out of it, and discovered that the conn was nil, and that caused the panic. Sorry for the trouble, and thanks for your help.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论