gpt4 book ai didi

go - 服务器和客户端之间明显的死锁

转载 作者:数据小太阳 更新时间:2023-10-29 03:11:50 26 4
gpt4 key购买 nike

我有一个测试函数,它既创建服务器又生成充当客户端的 goroutine。现在,只需从客户端向服务器发送一条消息就可以了,但是如果我想创建一个交换,它们似乎会死锁,因为测试永远不会运行到完成(如果没有设置 r/w 截止日期)。例如,我希望客户端向服务器发送消息,服务器复制该消息并将其发送回客户端,然后客户端验证接收到的消息是否相同。这是我的测试代码:

func TestSendAwait(t *testing.T) {
m := "Hello World"

go func() {
conn, err := net.Dial("tcp", testingAddr)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
t.Log("client connected to server") // DEBUG

conn.SetDeadline(time.Now().Add(2 * time.Second))
conn.Write([]byte(m))

conn.SetDeadline(time.Now().Add(2 * time.Second))
buf, err := ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
}
t.Log(string(buf))
}()

ln, err := net.Listen("tcp", testingAddr)
if err != nil {
t.Fatal(err)
}
defer ln.Close()
t.Log("server started") // DEBUG

conn, err := ln.Accept()
if err != nil {
t.Fatal(err)
}
defer conn.Close()
t.Log("server received connection") // DEBUG

buf, err := ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
}
t.Logf("server read buffer: %v", buf) // DEBUG

_, err = conn.Write(buf)
if err != nil {
t.Fatal(err)
}
t.Log("server wrote to connection") // DEBUG
}

截止日期是在连接上设置的,否则死锁将是无限期的。输出结果如下:

    transmission_test.go:42: server started
transmission_test.go:24: client connected to server
transmission_test.go:49: server received connection
transmission_test.go:32: read tcp 127.0.0.1:41164->127.0.0.1:9090: i/o timeout
transmission_test.go:55: server read buffer: [72 101 108 108 111 32 87 111 114 108 100]
transmission_test.go:61: server wrote to connection

Process finished with exit code 1

我不明白为什么客户端无法读取并退出,然后服务器才决定通过套接字发送数据?即使我增加客户端的读取截止日期,也会发生这种情况。

最佳答案

程序在调用 ioutil.ReadAll 时阻塞。此函数读取直到返回 io.EOF 或其他一些错误。

一个修复方法是在将数据写入连接后关闭写入。这将导致对等方的读取返回 io.EOF 并使 ioutil.ReadAll 成功返回。

    conn.Write(data)
cw, ok := conn.(interface{ CloseWrite() error })
if !ok {
// handle error
}
cw.CloseWrite()

playground example

问题中的程序不保证在拨号连接之前打开监听器或者客户端打印接收到的消息。 Playground 示例纠正了这些问题。

另一种方法是以某种方式构建消息:

  • 在一条又一条消息中写入换行符或其他不允许在消息中使用的字节序列。一直读到找到这个字节序列。
  • 在消息前写消息长度。读取长度,然后指定字节数。

关于go - 服务器和客户端之间明显的死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49593231/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com