推荐文章:https://winddoing.github.io/post/33577.html#%E8%BF%94%E5%9B%9E%E5%80%BC-n-x3D-x3D-0
推荐文章:https://blog.csdn.net/hguisu/article/details/38700899
今天线上服务器报错 Connection reset by peer ,为了一探究竟,所以来复现一下当时的场景。
示例代码
server 伪代码
server.listen("127.0.0.1",1234)
clientSock = server.accept()
whilt true{
msg = clientSock.recv()
print(msg)
sleep(1)
serverMsg = "server say" + rand.int()
clientSock.send(serverMsg)
}
client伪代码
sock = createSocket()
sock.connect("127.0.0.1",1234)
while true{
clientMsg = "client say" + rand.int()
sock.send(clientMsg)
sleep(2)
msg = sock.recv()
print(msg)
}
执行结果
具体代码有不同实现方式,但是过程都是上面的形式,我这里使用lua调用底层c++。
server
client
服务器先开起来,然后客户端连接上去,在服务器调用完send之后,立刻把server进程杀掉。
这个时候执行send把数据发送到tcp待发送缓冲区中,接下来client执行 recv方法的时候就会报错 Connection reset by peer。
Wireshark抓包验证
使用Wireshark进行抓包,可以看到在1584处向server发送了 ctl+c 命令,杀掉了进程,那么这是进程就交由Linux 0号进程管理(所有进程的父进程);0号进程对其进行资源回收,向client发送了 FIN 结束请求,收到client ACK 回复之后 server最后向client socket发送了 RST 消息,此时客户端再去 recv 的时候就会报 “socket:read: Connection reset by peer” 错误。
TCP RST消息的三种情况:
- 访问不存在的端口。若端口不存,则直接返回RST,同时RST报文接收通告窗口大小为0。其实客户端向服务器的某个端口发起连接,如果端口被处于TIME_WAIT 状态的连接占用时,客户端也会收到RST
- 异常终止连接。一方直接发送RST报文,表示异常终止连接。一旦发送方发送复位报文段,发送端所有排队等待发送的数据都被丢弃。应用程序可以通过socket选项SO_LINGER来发送RST复位报文。
- 处理半打开连接。一方关闭了连接,另一方却没有收到结束报文(如网络故障),此时另一方还维持着原来的连接。而一方即使重启,也没有该连接的任何信息。这种状态就叫做半打开连接。而此时另一方往处于半打开状态的连接写数据,则对方回应RST复位报文。
RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。