我正在使用TCP编写一个简单的TLV样式服务,该服务应该能够处理多个连接,并允许在同一连接上发送多个消息。
我需要确保长度不正确的消息不会无限期地阻塞连接,但是我需要确保后续消息可以在同一连接上发送而不会超时。
我正在使用io.ReadFull
读取固定数量的包含类型和长度的字节,然后当我收到length
时,我再次调用io.ReadFull
并读入length
个字节数。
如果我正在读取4个字节的类型和长度,但是客户端出于任何原因仅发送3个字节,则io.ReadFull
将挂起。同样,如果客户端发送300
作为长度,但长度应仅为200
,则io.ReadFull
将挂起,从而阻塞该通道上的所有通信。
在本示例中,我尝试使用conn.SetReadDeadline()
并将其设置为5秒。如果发送了不正确的长度,这将导致连接超时,这很好。问题是,如果下一个请求直到> 5秒后才发送,连接将会超时。
// ...
for {
conn, err := lis.Accept()
if err != nil {
fmt.Println(err)
continue
}
fmt.Println("Connected")
go handleC(conn)
}
func handleC(conn net.Conn) {
for {
err := conn.SetReadDeadline(time.Now().Add(5 * time.Second))
if err != nil {
fmt.Println(err)
break
}
l, err := readTL(conn)
if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
fmt.Println("Timeout", err)
break
}
fmt.Println("Other error"), err
break
}
v, err := readV(conn, l)
if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
fmt.Println("Timeout", err)
break
}
fmt.Println("Other error"), err
break
}
// go doStuffWithv()
}
}
func readTL(conn net.Conn) (l int, err error) {
buf := make([]byte, 4)
n, err := io.ReadFull(conn, buf)
if err != nil {
return l, err
}
fmt.Printf("Read %d bytes\n", n)
// getLengthFromTL()
return l, err
}
func readV(conn net.Conn, l int) (v []byte, err error) {
buf := make([]byte, l)
n, err := io.ReadFull(conn, buf)
if err != nil {
return v, err
}
fmt.Printf("Read %d bytes\n", n)
return v, err
}
如果客户端发送一个具有适当TL的请求,则事情将按预期进行。
但是,如果同一客户端在10秒钟内未发送第二条消息,则连接将在此之前超时,并显示错误tls: use of closed connection
有没有办法确保不会发生这种情况?
我尝试做的一件事是发生超时,它只是继续而不是中断。
我添加了另一个错误检查,以查看它是否为EOF
,如果是则中断。
我的第一印象是这种方法有效,但是我不确定是否存在连接超时的情况可能意味着该连接已死并且不应再使用,或者是否总是返回一个{ {1}}错误。