从另一个程序控制C守护进程
我试图从另一个用户空间程序控制一个C守护程序 -简单C守护进程 这个守护进程只是一个C程序,它对自身进行守护并通过syslog每秒记录一条消息从另一个程序控制C守护进程,c,linux,daemon,interprocess,C,Linux,Daemon,Interprocess,我试图从另一个用户空间程序控制一个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 start
#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程序中启动并杀死守护进程,但是我希望在某些特定情况下改进其行为
-处理守护进程崩溃
守护进程可能会在某个点失败,在这种情况下,应该通知控制程序,以便重新启动它。我的问题是检测守护进程是否已停止
我曾经考虑过通过调用pclose
来启动一个等待守护进程终止的线程,但是它不会工作,因为守护进程已经关闭了文件描述符并分离了进程
因此,我正在寻找在守护进程退出时通知程序的最佳方法
我可以使用带有exec
系列的linux调用进行轮询(例如pgrep daemon test
或ps aux|grep daemon test
),但我认为有更有效的方法来实现这一点
-处理测试程序错误
如果测试程序在杀死守护进程之前被杀死或失败,那么在下一次执行时,守护进程的两个实例将同时运行
测试程序日志:
系统日志:
我想通过检查是否已经有守护进程实例在运行来避免这种情况。如果没有,我可以从控制程序启动守护进程
否则,如果守护进程的一个或多个实例正在运行,我将在启动新实例之前杀死它们
这可以通过调用killall daemon test
来实现,但是每次执行时调用这个命令并不能满足我的要求,因为它在大多数情况下都是无用的
此外,我想明确记录每次执行时的情况,尽管我想知道在这种情况下有多少实例正在运行
同样,这可以通过linux命令调用轻松解决,但我正在寻找最有效的方法
有人知道我如何在不依赖linux命令调用的情况下实现守护进程控制吗?
编辑:2018年6月26日 我应该从一开始就对其进行精确化,但我的目标是能够监控守护进程,而不必修改其代码
因此,守护进程不会将其pid写入文件,并且始终与调用程序分离。与其通过
popen
运行程序,不如使用旧的POSIXfork
+exec
?它给了你更多的灵活性
现在,回答你的问题:
我的问题是检测守护进程是否已停止
要做到这一点,您必须在父/控制过程中收听SIGCHLD
信号。这已经足够好了,因为您直接调用了流程。但是,如果您调用一个shell脚本,然后将其分叉给您的守护进程,这将变得很困难。这就是为什么大多数守护进程都会编写一个名为pid
文件的文件——一个早期由守护进程编写的文件,其pid是该文件中唯一的内容。通常,人们会把它放在/tmp/mydaemon.pid
之类的地方
在Linux上,您的控制进程可以从该文件中读取PID,然后您可以每秒测试/proc//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等,以更好地了解它们是如何实现此功能的。您可以在守护进程中运行套接字服务器,然后使用control client作为普通CLI。CLI向守护进程发送测试消息或控制命令,守护进程给出响应。根据来自守护进程的响应,CLI可以监视守护进程的状态并控制它。是否尝试过系统调用:?
kill()
如果我有它的pid,或者它与调用方在同一进程组中,则最好杀死守护进程。因此,这可能是一个解决方案,但是守护进程已将守护进程与其父进程分离,因此它不再位于同一进程组中,因此我必须获取守护进程pid。这就是为什么守护进程将其pid写入/var/run.um的原因。。。从系统管理员的角度来看,发行版的init服务(upstart、systemd等等)不应该负责启动守护进程并保持其运行吗?当然,您的其他启动/停止代码-就像apache2ctl
。同样,从系统管理员的角度来看,我会给你的控制器程序添加一个状态检查,然后编写systemd配置文件,并将其打包成任何发行版。@Ivan通常我会使用systemd unit file或system V init脚本,但是我想克服这种init系统的使用。在使用fork
+execl
重新实现popen
后,我尝试了返回子pid,只要守护进程将其pid写入文件或不进行守护,这似乎是一个很好的解决方案。我宁愿不修改守护程序的代码,所以我会记住这个解决方案,以防没有其他解决方案能更好地满足我的需要start-stop-daemon
与您的解决方案相结合,允许我在不修改守护程序代码的情况下执行此操作。
$ ./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 !
$ ./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 !
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;
}
}