目的:利用守护线程实现程序自启。
1.shell脚本
#!/bin/sh
#添加本地执行路径
export LD_LIBRARY_PATH=./
while true; do
#启动一个循环,定时检查进程是否存在
server=`ps aux | grep a.out | grep -v grep`
if [ ! "$server" ]; then
#如果不存在就重新启动
./a.out
#启动后沉睡10s
sleep 1
echo "reboot"
fi
#每次循环沉睡10s
sleep 2
echo "this is sleep 5"
done
// g++ test.cpp
#include <iostream>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
using namespace std;
int main() {
while (1) {
printf("this is me\n");
sleep(1);
}
}
- 举个简单的例子:编译以下文件并执行g++ test.cpp,然后./a.out,在终端可看到每隔1s打印一次"this is me"
- 然后ps aux可看到正在执行的程序a.out的PID
- 执行脚本sh .daemon.sh
- 手动杀死线程kill PID
- 然后可看到test程序重启,并实时的打印"this is me",达到了通过脚本来重启程序的目的
2.查看/proc目录下是否有这个线程
首先要有一个概念,每一个被创建的线程都会放在proc文件夹下,而在proc文件夹的以线程ID命名的文件夹里面都包含有一堆关于这个线程ID的相关信息。而正在执行的程序名字就在/proc/[PID]/status文件夹内。
随便进入proc的某个线程文件夹,然后cat status,即可看到相关信息。操作步骤如下,即可看到这个执行的程序的名字。。
所以思路就是:
1.遍历/proc文件夹下所有的进程ID,然后用fopen去读/proc/[进程ID]/status的文件内容。如果有这个ID,并且读出文件的Name和预期的一样,就证明这个程序存在。
2.当遍历了所有的/proc/[进程ID]/status也没有找到我们想要的这个线程名字(a.out),就用execl("./a.out")重启这个程序。。
参考代码:仅有找到/proc/[PID]/status文件的Name是否与预期结果相同的代码。。。具体操作见代码前面的注释。。
// 在/proc文件下去解析某个程序的运行状态,名字----
// 读/proc/597097/status文件的Name与 ./a.out test的test是否一致
// execv("/proc/self/exe", exec_argv); 重启程序
// 编译:g++ get_running_program.cpp
// 执行:./a,out test
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <dirent.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
// get pid by program name
int main (int argc, char* argv[])
{
DIR *pdir = NULL;
struct dirent *pde = NULL;
FILE *pf = NULL;
char buff[128];
char buff2[128];
char *pstr = NULL;
int pid, ppid;
int n;
int i;
pdir = opendir("/proc");
if (!pdir)
{
perror("open /proc fail.\n");
return -1;
}
while ((pde = readdir(pdir))) // 遍历读出目录中的所有线程目录
{
if ((pde->d_name[0] < '0')
|| (pde->d_name[0] > '9'))
{
continue;
}
sprintf(buff, "/proc/%s/status", pde->d_name);
printf("path = %s\n",buff);
pf = fopen(buff, "r");
if (pf)
{
n = fread(buff, 1, 127, pf);
printf("buff = %s\n",buff);
fclose(pf);
buff[n] = 0;
for (i = 0; i < n; i++)
{
if ('\n' == buff[i])
{
buff[i] = 0;
break;
}
}
printf("== (%s) ==\n", buff);
n = i;
for (i = 0; i < n; i++)
{
if ((' ' == buff[i]) || ('\t' == buff[i]))
{
break;
}
}
for (; i < n; i++)
{
if ((' ' != buff[i]) && ('\t' != buff[i]))
{
break;
}
}
printf("NAME: (%s)\n", buff + i);
if (0 == strcmp(buff + i, argv[1]))
{
printf("found %s, pid = %d\n", buff + i, atoi(pde->d_name));
break;
}
}
}
closedir(pdir);
return 0;
}
3.通过程序执行终端命令来解析命令的内容
通过终端命令即可看到有没有这个线程,那能不能得到ps出来在终端的内容呢?经查找资料是可以的。。
比如我们的执行程序名为:a.out ,于是调用命令即可看到正在运行的程序
参考代码如下:---然后如果需要PID,或者名字,就需要去网上找一下具体的grep用法,来得到想要的信息。。---参考代码仅解析得到了程序a.ou的线程ID
// 如何调用【linux】shell命令行命令并获取命令行的输出内容
#include <stdio.h>
#include <string.h>
void executeCMD(const char *cmd, char *result)
{
char buf_ps[1024];
char ps[1024]={0};
FILE *ptr;
strcpy(ps, cmd);
if((ptr=popen(ps, "r"))!=NULL) //执行命令,返回的字符串指针ptr
{
while(fgets(buf_ps, 1024, ptr)!=NULL)
{
// 可以通过这行来获取shell命令行中的每一行的输出
// printf("%s", buf_ps);
strcat(result, buf_ps);
if(strlen(result)>1024)
break;
}
pclose(ptr);
ptr = NULL;
}
else
{
printf("popen %s error\n", ps);
}
}
int main()
{
char result[1024]={0};
executeCMD("ps aux | grep ./a.out | awk '{print $2}'", result); // 得到a.out的PID
// 这行是将每一行的输出拼接之后获取到了result字符串中了
printf("%s", result);
return 0;
}