3

我有一个服务器,它监听套接字连接并根据请求执行不同类型的操作。其中之一是长期存在的数据库查询,服务器为此分叉。

服务器保留所有活动子节点的日志,并且每当被要求关闭时,它会在退出之前杀死所有子节点。有几次我遇到服务器崩溃或被不优雅地杀死的情况,这导致子进程成为孤儿。如果我再次尝试恢复服务器,它将拒绝说监听套接字无法绑定,因为该地址/端口已经绑定。

我正在寻找一种方法来改善这种情况,以便主服务器进程可以立即恢复。我已经尝试从孩子那里监视父母的存在并在消失后立即退出,但这只会导致僵尸进程并且套接字似乎仍然被绑定。

该服务器是用 Python 编写的,但欢迎任何语言的任何解释或建议。

4

3 回答 3

2

使您的服务器成为进程组的领导者。在这种情况下,当组长退出时,孩子会被终止。

在类 Unix 系统上使用文本用户界面时,会话用于实现登录会话。单个进程(会话领导者)与控制终端交互,以确保在用户“挂断”终端连接时终止所有程序。(如果没有会话负责人,则终端的前台进程组中的进程应处理挂起。)

于 2009-05-15T01:05:44.490 回答
1

在你调用listen()之前在你的socket上使用它:

int on = 1;
setsockopt (sockfd_wan, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));

它允许您的程序使用该套接字,即使它之前是由另一个传出 TCP 连接随机选择的(对于 <1024 的端口不会发生)。但它也应该直接帮助您解决问题!!

无关:

还有可能发生的另一件坏事:如果您的孩子被分叉,他们会继承每个打开的文件描述符。如果他们只是简单地分叉并启动另一个长时间运行的程序,那么这些程序也会有一个打开的监听套接字句柄,因此它会继续使用(使用 lsof 和 netstat 命令查找!)

所以应该这样称呼:

int close_on_exec_on(int fd)
{
  return fcntl(fd, F_SETFD, FD_CLOEXEC);
}

close_on_exec_on(sockfd);

但是我从来没有在主程序中尝试过它,如果它分叉了孩子,它显然不会帮助你,因为孩子是分叉的,而不是与 exec 一起运行。

但请记住,无论如何都要在主程序的监听套接字上调用它!以防万一您运行外部程序

于 2009-05-14T23:14:15.867 回答
0

也许当你分叉时,不承认孩子,这样父进程就不是向操作系统注册的父进程。父母真的需要和孩子交流吗?如果不是,这可能是一个选择。

您可以跟踪子进程,但方式不同。您将不会再收到 SIGCHLD 事件。

于 2009-05-14T21:45:27.887 回答