我正在尝试从另一个用户空间程序控制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);
}
出于测试目的,我开发了一个最小的示例。我使用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
启动一个线程来等待守护进程终止,但是由于守护进程已经关闭了文件描述符并分离了进程,所以它不起作用。
所以我正在寻找使程序在守护程序退出时得到通知的最佳方法。
我可以使用带有exec
系列(例如pgrep daemon-test
或ps aux | grep daemon-test
)的linux调用进行轮询,但是我认为有更有效的方法来实现这一目标。
如果测试程序在杀死守护程序之前被杀死或失败,则在下一次执行时,该守护程序的两个实例将同时运行。
测试程序日志:
$ ./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写入文件,并且始终与调用方分离。
答案 0 :(得分:1)
为什么不使用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;
}
}
实际上,这大约是实现了多少个初始化系统。请参阅rc,systemd,upstart等,以更好地了解他们如何实现此目标。
答案 1 :(得分:0)
您可以在守护程序中运行套接字服务器,然后将控制客户端用作普通的CLI。 CLI将测试消息或控制命令发送到守护程序,守护程序给出响应。根据守护程序的响应,CLI可以监视并控制守护程序的状态。