我有一个测试功能,它既可以创建一个服务器,也可以生成一个充当客户端的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
我不明白为什么客户端无法读取和退出,只有服务器决定从套接字发送数据?即使我增加了客户端的读取截止日期,也会发生这种情况。
答案 0 :(得分:1)
程序会阻止对ioutil.ReadAll的调用。此函数读取,直到返回io.EOF或其他一些错误。
一种解决方法是在将数据写入连接后关闭写入。这将导致读取对等体返回io.EOF并使ioutil.ReadAll成功返回。
conn.Write(data)
cw, ok := conn.(interface{ CloseWrite() error })
if !ok {
// handle error
}
cw.CloseWrite()
问题中的程序不保证在拨打连接之前打开侦听器,或者客户端将打印打印收到的消息。操场示例纠正了这些问题。
另一种方法是以某种方式构建消息: