我正在使用 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
Is there a way to ensure that not occur?
我尝试做的一件事是在超时的情况下,它只是继续,而不是中断。我添加了另一个错误检查以查看它是否是EOF
,如果是则中断。
我的第一印象是这可行,但我不确定是否存在连接超时可能意味着连接已死并且不应再使用的情况,或者是否总是会返回EOF
错误。