我有一个服务器进程和一个客户端进程在同一台 Linux 计算机上运行。
有时,当我kill -9
作为客户端时,我会看到tcpdump
一条FIN, ACK
消息已发送。当然,死去的客户不可能做到这一点,因为他已经残酷地死去了SIGKILL
。所以我猜想 Linux 操作系统会处理连接关闭。
有时我看不到任何连接关闭处理,并且连接保持“已建立”状态(由netstat
)。
我总是看到连接被关闭Linux ubuntu 4.4.0-53-generic
。
有时Linux 3.13.11
我看到一个连接在(纯内核,而不是 Ubuntu)中被关闭。
我的问题是:
- Linux 是否处理关闭连接?
1.1 在SIGKILL
?
1.2.当应用程序正确关闭但不调用时close()
? - 此功能在内核版本之间是否发生变化
3.13.11
?4.4.0
Ubuntu 有什么相关的吗? - 如果这两个进程不在同一台 Linux 机器上怎么办:它的行为会相同吗?
- 为什么连接有时会保持“已建立”状态?
- 我知道 TCP
keepalive
套接字选项。如果 Linux 真的处理关闭连接。它们为何存在?仅当FIN, ACK
数据包丢失时?
答案1
一个广泛的问题。也许有人可以权衡您关于特定内核版本之间的内核 TCP 堆栈的问题。
几个一般性答案:
从客户端
如果出现
SIGKILL
信号,内核将终止程序执行,并关闭进程的打开文件描述符。内核处理 TCP 套接字的方式与处理常规文件略有不同,因为它们需要刷新并经历 TCP 关闭过程。来自客户端的立即“FIN、ACK”和较长的套接字关闭之间的差异可能取决于客户端应用程序终止时客户端 TCP 连接所处的状态。但通常内核会关闭应用程序打开的套接字。
从服务器端
服务器并不总是知道客户端何时断开连接。确定客户端是否已挂起的最可靠方法是尝试从返回 EOF 的套接字进行读取。
TCP 旨在能够适应连接延迟和间歇性故障。这也转化为在
FIN, ACK
没有发生 4 路断开握手的情况下可靠地检测断开的一些挑战。
概括
您可能会在kill -9
客户端看到服务器进入CLOSE_WAIT
TCP 状态,等待 TCP 超时。这可能需要一段时间。即使客户端消失了,如果内核没有处理 TCP 断开握手,服务器也将不得不超时。
如果我记得这可能需要额外几秒钟的时间,并且可能是您仍然看到的原因,ESTABLISHED
因为在同一主机上运行客户端和服务器。