Linux内核在进程死亡后,会在哪里进行进程和TCP连接清理?

8

我正在寻找Linux内核中处理进程死亡后的清理工作的地方。具体来说,我想查看它是否以及如何在使用-9信号杀死进程后处理打开的TCP连接。我相信它会关闭所有连接,但我想了解细节,并确定是否有任何可能连接没有正确关闭。

欢迎提供Linux内核源代码的指针。


我很好奇你是否找到了答案,如果是内核问题或网络问题的话。此外,更新你的问题会帮助那些后来遇到这个问题的人。 - JimB
@JimB,如果你对我们的网络问题感兴趣,那么不,我不知道问题是什么。我们添加了空闲连接检查并使用so_keepalive,但是由于有太多的流量,很难进行流量转储并验证某些数据包是否丢失。关于关闭,我检查了caf在他的答案中提到的源代码,并且我相信Linux内核至少会尝试在进程被杀死时关闭套接字。它是否成功还是另一个问题。 - Peter Štibraný
2个回答

13

进程终止的核心处理由exit.c:do_exit()函数处理。该函数调用exit_files(),后者再调用put_files_struct(),最后调用close_files()

close_files()循环遍历进程打开的所有文件描述符(包括所有套接字),对每个文件描述符调用filp_close(),然后在struct file对象上调用fput()。当最后一个对struct file的引用被释放时,fput()会调用文件对象的.release()方法,在套接字中,这是net/socket.c中的sock_close()函数。


7

我相信套接字的清理更多是在进程死亡后释放所有文件描述符的副作用,而不是直接由进程清理完成。

然而,我猜测你遇到了网络编程中的一个常见问题。如果我猜对了,你的问题是当进程被杀死后,尝试绑定地址时会出现“地址正在使用”的错误(EADDRINUSE),那么你就遇到了套接字的TIME_WAIT。

如果是这种情况,你可以等待超时,通常为60秒,或者修改套接字以允许立即重用,方法如下。

int sock, ret, on;
struct sockaddr_in servaddr;

sock = socket( AF_INET, SOCK_STREAM, 0 ):

/* Enable address reuse */
on = 1;
ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

从你的评论中,听起来你正在遇到半开连接的问题,而且不完全了解TCP的工作原理。TCP无法确定客户端是死亡还是闲置。如果您使用 kill -9 终止客户机进程,则四方关闭握手永远无法完成。但这不应该在服务器上留下打开的连接,所以您仍然需要获取网络转储文件以确保发生了什么事情。
由于我不知道你具体在做什么,所以不能确定你应该如何处理。但你可以阅读关于TCP Keepalive的文章。还有一些其他选项,例如定期向客户端发送空或空消息(可能需要修改协议),或对闲置连接设置硬计时器(可能会导致有效连接丢失)。

谢谢...清理文件描述符确实会导致连接关闭。顺便说一下,我遇到了不同的问题;-)我们的服务器看到已被-9杀死的客户端的过时连接,我们正在努力找出原因。目前的解决方案是自动关闭服务器上的空闲连接并使用SO_KEEPALIVE,但我们也在努力理解这个问题。 - Peter Štibraný
那么看起来你遇到了半开连接的问题。我会更新我的答案。 - JimB
谢谢更新。我昨天刚读了Tcp keepalive faq。我们也已经在服务器上添加了闲置连接的丢弃。修改协议以从服务器发送“ping”不是一个选项,但我们将结合SO_KEEPALIVE和闲置连接的丢弃,这应该对我们有用。让我困惑的是,当我在本地使用kill -9时,内核尝试很好地关闭此连接。顺便说一下,客户端和服务器都在我们控制的同一网络中,我们只在一个部署中看到了这个问题。 - Peter Štibraný
你可能需要获取网络流量转储来确定问题。现在我想了想(并得到了@caf的证实),即使使用 kill -9 命令也应该让套接字关闭,并将服务器置于 CLOSE_WAIT 状态,这不应该真正引起问题。我所描述的半开放状态通常是由电源、链路或路由问题引起的,客户端会突然消失。 - JimB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接