警惕系统中那些异常的 RST

认真学习协议栈很重要

Posted by ms2008 on July 23, 2017

我们的系统有一个应用启用了连接池来连接后端的应用,最近我却发现这个连接池貌似并不能正常工作。理论上来说,当启用了连接池,应用到后端的连接应该稳定才对,而我通过 ss 观察到的现象却是应用不断的建立连接,断开连接。更为奇怪的是,应用方并没有出现 TIME_WAIT。起初我怀疑是服务端主动关闭了连接,但是在服务端也并没有发现 TIME_WAIT,所以可以基本排除这个问题。

之后抓了下包才发现,原来是应用端主动发了 RST 来终止连接:

但是应用是正常通过 close() 系统调用来关闭连接的啊,理论上是应该发 FIN 的,为什么会发送 RST 呢?google 了一番,在 @淘宝褚霸 的 blog 找到了答案:

如果你的接收缓冲去还有数据,协议栈就会发 RST 代替 FIN.

我们再来验证一下:

  • 接收缓冲区还有数据,发 RST
local socket = require("socket")

local host, port = "www.baidu.com", 80
local sock = socket.connect(host, port)
sock:settimeout(1)
sock:send("GET / HTTP/1.1\r\n\r\n")
sock:close()

  • 接收缓冲区读取干净了,发 FIN
local socket = require("socket")

local host, port = "www.baidu.com", 80
local sock = socket.connect(host, port)
sock:settimeout(1)
sock:send("GET / HTTP/1.1\r\n\r\n")

while true do
    local line, err = sock:receive()
    if err == "timeout" then
        break
    end
end
sock:close()

最后推荐大家使用 nicstat 来监控系统的 RST 情况: