从另一个程序控制C守护程序 [英] Controlling a C daemon from another program

查看:83
本文介绍了从另一个程序控制C守护程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从另一个用户空间程序控制C守护程序。

I'm trying to control a C daemon program from another userspace program.

该守护进程只是一个C程序,它可以自我守护并每秒通过syslog记录一条消息。

This daemon is simply a C program which daemonize itself and log a message every second through 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 启动守护程序,因为我希望我的程序继续执行。

- Launching and killing the daemon from a C test program

For test purpose I have developped a minimal example. I'm using popen to launch the daemon because I want my program to continue its execution.

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;
}

测试程序日志:

Test program log:

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

系统日志:

Syslog:

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程序启动并杀死守护程序,但是我想改善某些特定情况下的行为。

So I'm able to launch and kill the daemon from my C program, however I would like to improve the behaviour in some specific cases.

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

The daemon may fail at some point, in that case the control program should be notified so it can be relaunched. My problem is to detect that the daemon has been stopped.

我有一个关于启动线程等待守护程序终止的线程,方法是调用 pclose ,但是由于守护进程已关闭文件描述符并分离了该进程,因此无法正常工作。

I have though about launching a thread waiting for daemon termination by a call to pclose, however it won't work as the daemonization has already closed file descriptors and detached the process.

所以我正在寻找最佳方法

So I'm looking for the best way to have the program notified on daemon exit.

我可以使用带有 exec 家族(例如 pgrep守护程序测试 ps aux | grep守护程序测试),但我认为有更有效的方法来实现。

I could poll using linux calls with exec family (such as pgrep daemon-test or ps aux | grep daemon-test) but I think there are more efficient way to achieve that.

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

If the test program is killed or fails before it kills the daemon, at next execution, two instances of the daemon will run at the same time.

测试程序日志:

Test program log:

$ ./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

系统日志:

Syslog:

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 !

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

I want to avoid this situation by checking if there are already daemon instances running. If not I can launch the daemon from control program.

否则,如果一个或多个守护程序实例正在运行,则在启动新守护程序之前将其杀死。

Otherwise if one or several instances of the daemon are running I shall kill them before launching a new one.

这可以通过调用 killall daemon-test 来实现,但是每次执行时调用此命令都不会让我满意,因为它没有用

This could be achieved by calling killall daemon-test but calling this command at each execution doesn't satisfy me because it's useless most of the time.

此外,我想明确记录每次执行时的情况,尽管我想确切知道在这种情况下正在运行多少个实例。

Moreover I would like to explicitly log the situation at each execution and though I want to know exactly how many instances were running in that case.

可以再次使用linux命令轻松解决此问题,但我正在寻找最有效的方法。

Once again this can be resolved easilly using linux command calls, but I'm looking for the most efficient way to do it.

是否有人知道我可以如何实现守护进程控制而不必依靠linux命令调用?

编辑: 2018年6月26日

我应该有从一开始就将其精确化,但我的目标是能够监视守护进程而无需修改其代码。

I should have precised it from the beginning but my aim is to be able to monitor the daemon process without having to modify its code.

因此,守护进程不会将其pid写入文件,并且始终是分离的

So the daemon doesn't write its pid to a file and is always detached from its caller.

推荐答案

而不是通过 popen 运行程序不使用旧的POSIX fork + exec

Instead of running the program via popen why not use the good old POSIX fork + exec? It gives you a bit more flexibility.

现在,回答您的问题:


我的问题是检测到守护程序已停止。

My problem is to detect that the daemon has been stopped.

要执行此操作,您必须听 SIGCHLD 在您的父/控制过程中发出信号。这已经足够好了,因为您直接调用了该过程。但是,如果您调用了一个shell脚本然后分叉了守护程序,那将变得很困难。这就是为什么大多数守护程序都编写称为 pid 文件的原因-文件是由守护程序在早期以其PID编写的文件中唯一的内容。通常,人们把它放在 /tmp/mydaemon.pid 之类。

To do this you have to listen to SIGCHLD signal in your parent/controlling process. This is good enough since you directly invoked the process. But if you called a shell script which then forked your daemon, it would get difficult. This is why most daemons write something called a pid file - A file written by the daemon early on with it's PID as the only content in that file. Normally, people have it put it /tmp/mydaemon.pid or something like that.

在Linux上,您的控制进程可以从该文件读取PID,然后可以每秒检查 / proc /< pid> / exe 文件是否存在。如果不是,您知道守护程序已死。例如,如果子程序的PID为1234,则 / proc / 1234 / exe 将是到子程序可执行文件实际位置的软链接。

On Linux, your controlling process can read the PID from this file, then every second you can test if /proc/<pid>/exe file exists. If not, you know the daemon died. For example, if your child program's PID is 1234, then /proc/1234/exe will be a soft link to the actual location of the executable of the child program.

类似这样的东西:

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;
    }
}

实际上,这实际上是多少个初始化系统已实施。请参阅rc,systemd,upstart等,以更好地了解他们如何实现此目标。

In fact, this is roughly how many init systems are implemented. See rc, systemd, upstart etc. for a better understanding of how they implement this in more details.

这篇关于从另一个程序控制C守护程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆