Handle ‘connection reset by peer’ error in Go
TCP连接在对端异常关闭,并发送RST包过来重建连接时,连接会报connection reset by peer
错误,正常关闭连接会发送FIN包。
当连接接收到这类错误时,在Go中可以通过检测连接返回错误是否为syscall.ECONNRESET
来判断
重现connection reset by peer
错误
重现步骤:
- 服务端读取一个字节后关闭连接
- 客户端发送多个字节数据包
当还有剩余数据在连接缓冲中没有读取,服务端关闭连接,则会发送RST数据包给客户端,
客户端尝试从关闭的连接读取数据时,就会返回connection reset by peer
错误。
模拟错误场景示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
package main
import (
"errors"
"log"
"net"
"os"
"syscall"
"time"
)
func server() {
listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
conn, err := listener.Accept()
if err != nil {
log.Fatal("server", err)
os.Exit(1)
}
data := make([]byte, 1)
if _, err := conn.Read(data); err != nil {
log.Fatal("server", err)
}
conn.Close()
}
func client() {
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
log.Fatal("client", err)
}
if _, err := conn.Write([]byte("ab")); err != nil {
log.Printf("client: %v", err)
}
time.Sleep(1 * time.Second) // wait for close on the server side
data := make([]byte, 1)
if _, err := conn.Read(data); err != nil {
log.Printf("client: %v", err)
if errors.Is(err, syscall.ECONNRESET) {
log.Print("This is connection reset by peer error")
}
}
}
func main() {
go server()
time.Sleep(3 * time.Second) // wait for server to run
client()
}
|
输出结果:
1
2
|
2022/07/31 11:25:30 client: read tcp [::1]:62301->[::1]:8080: read: connection reset by peer
2022/07/31 11:25:30 This is connection reset by peer error
|
注:这只是模拟发生connection reset by peer
错误的一种情况,在实际项目中,可能由更多复杂情况导致。
针对不同的情况,需要更加深入了解TCP设计,并结合实际情况分析获得。