代码之家  ›  专栏  ›  技术社区  ›  Arkaik zx81

从另一个程序控制c守护进程

  •  0
  • Arkaik zx81  · 技术社区  · 6 年前

    我试图从另一个用户空间程序控制一个c守护程序程序。

    -简单C守护程序

    这个守护进程只是一个c程序,它对自己进行守护,并通过syslog每秒记录一条消息。

    #include <stdlib.h>
    #include <stdio.h>
    #include <syslog.h>
    #include <unistd.h>
    #include <signal.h>
    
    void bye();
    
    int main()
    {
      printf("Daemon starting ...\n");
      openlog("daemon-test", LOG_PID, LOG_DAEMON);
      signal(SIGTERM, bye);
    
      if(0 != daemon(0, 0))
      {
        syslog(LOG_ERR, "Can't daemonize\n");
        return EXIT_FAILURE;
      }
    
      syslog(LOG_INFO, "Daemon started !\n");
    
      while(1)
      {
        syslog(LOG_INFO, "Daemon alive\n");
        sleep(1);
      }
    
      return EXIT_SUCCESS;
    }
    
    void bye()
    {
      syslog(LOG_INFO, "Daemon killed !\n");
      exit(EXIT_SUCCESS);
    }
    

    -从C测试程序启动和终止守护进程

    为了测试的目的,我开发了一个最小的例子。我在用 popen 启动守护进程,因为我希望我的程序继续执行。

    5秒后,测试程序应该会终止守护进程。

    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    
    #define DAEMON_NAME       "daemon-test"
    
    int main()
    {
        FILE* pipe = NULL;
        int i = 0;
    
        printf("Launching '%s' program\n", DAEMON_NAME);
        if(NULL == (pipe = popen(DAEMON_NAME, "re")))
        {
            printf("An error occured launching '%s': %m\n", DAEMON_NAME);
            return EXIT_FAILURE;
        }
        printf("Program '%s' launched\n", DAEMON_NAME);
    
        while(i<5)
        {
            printf("Program alive !\n");
            sleep(1);
            i++;
        }
    
        if(NULL == (pipe = popen("killall " DAEMON_NAME, "re")))
        {
            printf("An error occured killing '%s' program: %m\n", DAEMON_NAME);
            return EXIT_FAILURE;
        }
        printf("Program '%s' killed\n", DAEMON_NAME);
    
        return EXIT_SUCCESS;
    }
    

    测试程序日志:

    $ ./popenTest 
    Launching 'daemon-test' program
    Program 'daemon-test' launched
    Program alive !
    Program alive !
    Program alive !
    Program alive !
    Program alive !
    Program 'daemon-test' killed
    

    系统日志:

    Jun 25 13:58:15 PC325 daemon-test[4445]: Daemon started !
    Jun 25 13:58:15 PC325 daemon-test[4445]: Daemon alive
    Jun 25 13:58:16 PC325 daemon-test[4445]: Daemon alive
    Jun 25 13:58:17 PC325 daemon-test[4445]: Daemon alive
    Jun 25 13:58:18 PC325 daemon-test[4445]: Daemon alive
    Jun 25 13:58:19 PC325 daemon-test[4445]: Daemon alive
    Jun 25 13:58:20 PC325 daemon-test[4445]: Daemon alive
    Jun 25 13:58:20 PC325 daemon-test[4445]: Daemon killed !
    

    所以我可以从我的c程序中启动并杀死守护进程,但是我想在某些特定情况下改进行为。

    -处理守护进程崩溃

    守护进程可能在某个时刻失败,在这种情况下,应该通知控制程序,以便可以重新启动它。我的问题是检测守护进程是否已停止。

    我想启动一个线程,等待通过调用 pclose 但是,它不能工作,因为子进程已经关闭文件描述符并分离进程。

    所以我在寻找在后台程序退出时通知程序的最佳方法。

    我可以使用linux调用 exec 家庭(例如 pgrep daemon-test ps aux | grep daemon-test )但我认为有更有效的方法来实现这一点。

    -处理测试程序错误

    如果测试程序在杀死守护进程之前被杀死或失败,在下一次执行时,守护进程的两个实例将同时运行。

    测试程序日志:

    $ ./popenTest 
    Launching 'daemon-test' program
    Program 'daemon-test' launched
    Program alive !
    Program alive !
    Program alive !
    ^C
    $ ./popenTest 
    Launching 'daemon-test' program
    Program 'daemon-test' launched
    Program alive !
    Program alive !
    Program alive !
    Program alive !
    Program alive !
    Program 'daemon-test' killed
    

    系统日志:

    Jun 25 14:17:25 PC325 daemon-test[4543]: Daemon started !
    Jun 25 14:17:25 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:26 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:27 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:28 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:29 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:29 PC325 daemon-test[4547]: Daemon started !
    Jun 25 14:17:29 PC325 daemon-test[4547]: Daemon alive
    Jun 25 14:17:30 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:30 PC325 daemon-test[4547]: Daemon alive
    Jun 25 14:17:31 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:31 PC325 daemon-test[4547]: Daemon alive
    Jun 25 14:17:32 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:32 PC325 daemon-test[4547]: Daemon alive
    Jun 25 14:17:33 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:33 PC325 daemon-test[4547]: Daemon alive
    Jun 25 14:17:34 PC325 daemon-test[4543]: Daemon alive
    Jun 25 14:17:34 PC325 daemon-test[4547]: Daemon alive
    Jun 25 14:17:34 PC325 daemon-test[4543]: Daemon killed !
    Jun 25 14:17:34 PC325 daemon-test[4547]: Daemon killed !
    

    我想通过检查是否已经有守护进程实例在运行来避免这种情况。如果没有,我可以从控制程序启动守护进程。

    否则,如果守护进程的一个或多个实例正在运行,我将在启动新的守护进程之前杀死它们。

    这可以通过调用 killall daemon-test 但是每次执行时调用这个命令并不满足我,因为大部分时间都是无用的。

    此外,我想显式地记录每次执行时的情况,尽管我想知道在这种情况下到底有多少实例在运行。

    再次强调,使用linux命令调用很容易解决这个问题,但我正在寻找最有效的方法来解决这个问题。

    有人知道我如何实现后台进程控制而不必依赖Linux命令调用吗?


    编辑: 2018年6月26日

    我应该从一开始就对它进行精确化,但我的目标是能够监视守护进程 没有 必须修改代码。

    因此守护进程不会将其pid写入文件,并且始终与其调用程序分离。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Unmanned Player    6 年前

    而不是通过 popen 为什么不使用好的旧posix fork + exec 是吗?它给你一点灵活性。

    现在,回答你的问题:

    我的问题是检测守护进程是否已停止。

    要做到这一点你必须听 SIGCHLD 在您的父/控制过程中的信号。这是很好的,因为您直接调用了这个过程。但是如果你调用了一个shell脚本,它会分叉守护进程,它就会变得困难。这就是为什么大多数守护进程编写称为 pid 文件-守护进程在早期编写的一个文件,它的pid是该文件中的唯一内容。通常,人们会把它放在 /tmp/mydaemon.pid 或者类似的事情。

    在Linux上,你的控制过程可以从这个文件中读取PID,然后你可以测试每秒钟。 /proc/<pid>/exe 文件存在。如果不是的话,你知道这个守护者死了。例如,如果您的子程序的PID为1234,则 /proc/1234/exe 将是指向子程序可执行文件的实际位置的软链接。

    像这样的:

    FILE *f;
    pid_t pid_child;
    char proc_path[256];
    
    f = fopen("/tmp/mydaemon.pid", "r");
    fscanf(f, "%d", &pid_child);
    fclose(f);
    sprintf(proc_path, "/proc/%d/exe", pid_child);
    
    while(1) {
        if (access(proc_path, F_OK) == 0) {
            printf("Program alive !\n");
            sleep(1);
        } else {
            printf("Program dead!\n");
            break;
        }
    }
    

    实际上,这大概是实现了多少个init系统。请参阅rc、systemd、upstart等,以更详细地了解它们是如何实现这一点的。

        2
  •  0
  •   Joy Allen    6 年前

    可以在后台程序中运行套接字服务器,然后将控制客户端用作普通的cli。CLI将测试消息或控制命令发送给守护进程,守护进程提供响应。cli可以根据守护进程的响应来监视和控制守护进程的状态。