参考:Linux下实现通过一个进程控制另一个进程的启动、停止、崩溃重启

有时候我们希望部署一些服务,而这些服务可能会在某种原因下崩溃,可能是bug或者其他原因,这个时候为了能继续维持服务,就将该服务进程挂在另一个进程下,达到自动重启的目的。这里的daemon守护进程不是后台程序,可以通过其他操作使其进入后台如nohup或者可以将代码改成真正的daemon后台守护进程。

使用gcc编译并运行

gcc -o daemon daemon.c -pthread
gcc -o test_app test.c
./daemon test_app
#可以加参数,不过在解析参数时有一点区别
#example: ./daemon test_app 192.168.0.2

可以使用systemd让程序成为系统服务,参考How to restart a process automatically when it killed in linux/CentOS,或者开机自启:

vim /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will exit 0 on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/bin/bash test_app.sh
exit 0

test_app.sh(注意需要使其有可执行权限chmod +x test_app.sh):

#!/bin/sh

cd /folder_to_app
./daemon test_app &

源代码如下(思考:如何做成免杀程序呢?):

//daemon.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>  
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

char glb_process[1024] = "";
char glb_arg[1024] = "";
int glb_pid = -1;

int create_process(const char* cmd, const char* arg)
{
    int pid = fork();
    if(pid == -1)
    {
        printf("fork error\n");
        return -1;
    }else if(pid == 0){
        int ret = execl(cmd, arg, NULL);
        if(ret < 0)
        {
            printf("execl : %s(%d)\n", strerror(errno), errno);
            return -2;
        }
    }
    return pid;
}

int kill_process(int pid)
{
    int ret = kill(pid, SIGKILL);
    if(ret < 0)
    {
        printf("kill : %s(%d)\n", strerror(errno), errno);
        return -1;
    }
    return 0;
}

int judge_proc_exist(int pid)
{
    DIR* dir;
    struct dirent* s_dir;
    struct stat file_stat;
    const char *proc_dir = "/proc/";
    char s_pid[10] = "";
    if((dir = opendir(proc_dir)) == NULL) 
    {
        printf("open %s error : %s(%d)", proc_dir, strerror(errno), errno);
        return 1;
    }
    sprintf(s_pid, "%d", pid);
    int found = 0;
    while((s_dir = readdir(dir)) != NULL) 
    {
        lstat(s_dir->d_name, &file_stat);
        if((!strcmp(s_pid, s_dir->d_name)) && (S_ISDIR(file_stat.st_mode))){
            found = 1;
            break;
        }
    }
    closedir(dir);
    return found;
}

void* entry_thread(void* user_data)
{
    glb_pid = create_process(glb_process, glb_arg);
    printf("Process(%d) start...\n", glb_pid);
    return 0;    
}

void sig_child(int signo)
{
    pid_t pid;
    int stat;
    pid = wait(&stat);    
    printf( "Process %d exit\n", pid );
    glb_pid = create_process(glb_process, glb_arg);
    printf( "Restart %d \n", glb_pid );
    return;
}

int main(int argc, char* argv[])
{
    pthread_t it;
    if(argc < 2)
    {
        printf("Usage : %s exe path [arg]\n", argv[0]);
        printf("build at %s %s\n", __DATE__, __TIME__);
        return -1;
    }
    if(argc > 1)
    {
        strcpy(glb_process, argv[1]);
    }
    if(argc > 2)
    {
        strcpy(glb_arg, argv[2]);
    }
    signal(SIGCHLD,  &sig_child);
    pthread_create(&it, NULL, entry_thread, NULL );
    while(1)
    {
       usleep(20*1000);
    }
}

测试程序

//test.c
#include <stdio.h>
#include <unistd.h>

int main(void)
{
   while(1)
   { 
      printf("Hello World!\n");
      usleep(1000*1000);
   }
   return 0;
}
Logo

更多推荐