【问题标题】:Handling ungraceful shutdowns when using fork and sockets使用 fork 和套接字时处理不正常的关闭
【发布时间】:2009-05-14 21:39:20
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你知道服务器是如何终止的吗?如果您可以在信号处理程序中发现问题,则可以退出子级。
  • 您确定子进程正在检测其父进程的消失并调用退出吗?如果父进程消失,init (pid 1) 应该继承子进程,在退出的子进程上调用 wait() 并且僵尸永远不会发生。

标签: unix sockets process fork zombie-process


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    它允许您的程序使用该套接字,即使它之前被另一个传出 TCP 连接随机选择(对于端口

    无关的:

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

    所以应该这样称呼:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-07
        • 2015-11-30
        • 2017-07-09
        • 2013-07-13
        • 1970-01-01
        • 1970-01-01
        • 2017-05-21
        • 1970-01-01
        相关资源
        最近更新 更多