找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4555|回复: 0

带有自动检测进程的Linux程序

[复制链接]
发表于 2013-10-11 10:27:16 | 显示全部楼层 |阅读模式
最近经常写一些需要自我维护且能自动启动的程序。
当然,最简单的方法是用一个shell去搞定,但是这个shell太粗俗了,如果我一个程序启动有7个进程,其中一个挂了,我就不得不重启7个所有的进程,这显然是不能让我满意的。
于是开发了一个小接口,通用代码,实现对当前程序所有进程的监控,时刻监控当前程序下的所有进程,如果有挂了的,立刻重启当前进程,其他进程不动,最大程度减少损失。
于是,于是,这个小程序就诞生了。
看看我用了什么东东。
首先是文件锁,这个东东很有用。
相关API是,fcntl
关于这个函数,我只用到了三个宏。
F_WRLCK   //加写锁
F_UNLCK   //解锁
F_GETLK   //得到锁当前的状态

作为测试用例,我故意启动了一个子进程,然后在程序外,直接强硬的kill掉这个子进程,我的目的是,这个程序会自己恢复这个子进程。
作料嘛,还差一点。
那就是一个文件,提供一个IO记录这个锁状态。
这里对锁操作,我封装了三个函数。
  1. //写独占文件锁
  2. int AcquireWriteLock(int fd, int start, int len)
  3. {
  4.         struct flock arg;
  5.         arg.l_type = F_WRLCK; // 加写锁
  6.         arg.l_whence = SEEK_SET;
  7.         arg.l_start = start;
  8.         arg.l_len = len;
  9.         arg.l_pid = getpid();
  10.         return fcntl(fd, F_SETLKW, &arg);
  11. }
复制代码
释放独占锁
  1. //释放独占文件锁
  2. int ReleaseLock(int fd, int start, int len)
  3. {
  4.         struct flock arg;
  5.         arg.l_type = F_UNLCK; //  解锁
  6.         arg.l_whence = SEEK_SET;
  7.         arg.l_start = start;
  8.         arg.l_len = len;
  9.         arg.l_pid = getpid();
  10.         return fcntl(fd, F_SETLKW, &arg);
  11. }
复制代码
查看独占锁
  1. //查看写锁
  2. int SeeLock(int fd, int start, int len)
  3. {
  4.         struct flock arg;
  5.         arg.l_type = F_WRLCK;
  6.         arg.l_whence = SEEK_SET;
  7.         arg.l_start = start;
  8.         arg.l_len = len;
  9.         arg.l_pid = getpid();
  10.         if (fcntl(fd, F_GETLK, &arg) != 0) // 获取锁
  11.         {
  12.                 return -1; // 测试失败
  13.         }
  14.         if (arg.l_type == F_UNLCK)
  15.         {
  16.                 return 0; // 无锁
  17.         }
  18.         else if (arg.l_type == F_RDLCK)
  19.         {
  20.                 return 1; // 读锁
  21.         }
  22.         else if (arg.l_type == F_WRLCK)
  23.         {
  24.                 return 2; // 写所
  25.         }
  26.         return 0;
  27. }
复制代码
好了,我模拟一个独立子进程
  1. int Chlid_Run()
  2. {
  3.         //测试子进程
  4.         struct timespec tsSleep;
  5.        
  6.   tsSleep.tv_sec  = 5;
  7.         tsSleep.tv_nsec = 0;       
  8.        
  9.         while(true)
  10.         {
  11.                 nanosleep(&tsSleep, NULL);
  12.         }
  13. }
复制代码
这里只是一个死循环,模拟子进程工作的动作。
实际生产环境中,我有若干个队列处理子进程,对应不同的msgqueue。有20个。
这里只是为了展示功能,并提供相应的测试代码,你可以在这里替换成你的代码。

好了,最后看看我的主程序如何实现吧。对了,再说一句,你要想玩它,你可以把nNumChlid设置成你喜欢的子进程数。
而实际我的生产环境代码比这个要多的多,主要是我把配置文件,子进程数量全部写到ini文件里面去了,直接读取配置文件从而实现自动配置管理。
并且我的进程挂掉的时候,我会自动输出到短信接口,并备份记录core文件,提示维护人员查看。配合core文件提供给开发人员分析错误。同时保证最大的业务运行。
关于这部分的代码,相信读者会自己实现的,就不在这里展示了。
  1. int main(int argc, char *argv[])
  2. {
  3.         //当前监控子线程个数
  4.         int nNumChlid = 1;
  5.        
  6.         //检测时间间隔参数
  7.         struct timespec tsRqt;
  8.        
  9.         //文件锁
  10.         int fd_lock = 0;
  11.        
  12.         int nRet = 0;
  13.         //主进程检测时间间隔(设置每隔5秒一次)
  14.   tsRqt.tv_sec  = 5;
  15.         tsRqt.tv_nsec = 0;
  16.        
  17.         // 打开(创建)锁文件
  18.         char szFileName[200] = {'\0'};
  19.         memset(szFileName, 0, sizeof(flock));
  20.         sprintf(szFileName, "%s/cfg/testwatch.lk", getenv("HOME"));
  21.         fd_lock = open(szFileName, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
  22.         if (fd_lock < 0)
  23.         {
  24.                 printf("open the flock and exit, errno = %d.", errno);
  25.                 exit(1);
  26.         }
  27.        
  28.         //查看当前文件锁是否已锁
  29.         nRet = SeeLock(fd_lock, 0, sizeof(int));
  30.         if (nRet == -1 || nRet == 2)
  31.         {
  32.                 printf("file is already exist!");
  33.                 exit(1);
  34.         }
  35.        
  36.         //如果文件锁没锁,则锁住当前文件锁
  37.   if (AcquireWriteLock(fd_lock, 0, sizeof(int)) != 0)
  38.         {
  39.                 printf("lock the file failure and exit, idx = 0!.");
  40.                 exit(1);
  41.         }
  42.        
  43.         //写入子进程锁信息
  44.         lseek(fd_lock, 0, SEEK_SET);
  45.         for (int nIndex = 0; nIndex <= nNumChlid; nIndex++)
  46.   {
  47.           write(fd_lock, &nIndex, sizeof(nIndex));
  48.   }
  49.   
  50.   while (1)
  51.   {
  52.        
  53.           for (int nChlidIndex = 1; nChlidIndex <= nNumChlid; nChlidIndex++)
  54.           {
  55.                      //测试每个子进程的锁是否还存在
  56.                      nRet = SeeLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int));
  57.                      if (nRet == -1 || nRet == 2)
  58.                      {
  59.                              continue;
  60.                      }
  61.                      //如果文件锁没有被锁,则设置文件锁,并启动子进程
  62.                      int npid = fork();
  63.                      if (npid == 0)
  64.                      {
  65.                              //上文件锁
  66.                              if(AcquireWriteLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int)) != 0)
  67.                 {
  68.                         printf("child %d AcquireWriteLock failure.\n", nChlidIndex);
  69.                         exit(1);
  70.                 }
  71.                 
  72.                 //启动子进程
  73.                 Chlid_Run();
  74.                  printf("schang debug 2\n");
  75.                 
  76.                                         //子进程在执行完任务后必须退出循环和释放锁
  77.                                         //ReleaseLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int));                
  78.                      }
  79.           }
  80.          
  81.           printf("child count(%d) is ok.\n", nNumChlid);
  82.           //检查间隔
  83.           nanosleep(&tsRqt, NULL);
  84.   }
  85.        
  86.         return 0;
  87. }
复制代码
对了,在补充一下它需要的头文件。
  1. #include <sys/types.h>
  2. #include <stdarg.h>
  3. #include <signal.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <time.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <errno.h>
复制代码
加上空行一共170行代码。
简单吧。
行了,编译运行吧
g++ -o test testwatch.cpp
运行一下,然后kill掉一个它的子进程,过5秒,看看是否自动起来了。
以上代码在Linux 64 Red Hat Enterprise Linux Server release 5.5 测试通过。


您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-11-21 18:37 , Processed in 0.021636 second(s), 9 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表