2012-08-05 23:58:31 xinxijisuan 阅读数 3821
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7161 人正在学习 去看看 良许
int forkprocess(void)
{
 printf("forkprocess   running......\r\n"); 
 pid_t pid = 0;
 int  status;
 
 while(1)
 {
  pid = fork();
  if(pid < 0)
  {
   printf("fork error............\r\n");
   exit(1);
  }
  if(pid == 0)
  {
   printf("this is child prodess return............\r\n");
   return 0;
  }
  printf("wait child prodess........\n");
  waitpid(pid, &status, 0);
  printf("child prodess end........\n");
 } 
 return 0;
}

2012-04-24 10:47:25 QQ276592716 阅读数 24204
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7161 人正在学习 去看看 良许

家在写server的时候,不管server写的是多么健壮,还是经常出现core dump等程序异常退出的,但是一般情况下需要在无人为干预情况下,能够自动重新启动,保证server程序能够服务用户。这时就需要一个监控程序来实现能够让程序自动重新启动,现在笔者在写portmap就遇到了这个问题,通过网上查找资料,找到了一个相对靠谱的exec+fork解决方法。

使用脚本实现自动重启

首先想到的最简单的使用shell脚本,大概思路:

ps -ef | grep “$1″ | grep -v “grep” | wc –l 是获取 $1 ($1 代表进程的名字)的进程数,脚本根据进程数来决定下一步的操作。通过一个死循环,每隔 1 秒检查一次系统中的指定程序的进程数,这里也可使用crontab来实现。

这种方法比较土,还是可以基本解决问题,但是有1s的延迟,笔者在应用中未采用这种方法,有关这个shell脚本,请参看文章后面的附件代码。

exec+fork方式

笔者最终采用的exec+fork方式来实现的,具体思想如下:

1,exec函数把当前进程替换为一个新的进程,新进程由path或file参数指定。可以使用exec函数将程序的执行从一个程序切换到另一个程序;

2,fork函数是创建一个新的进程,在进程表中创建一个新的表项,而创建者(即父进程)按原来的流程继续执行,子进程执行自己的控制流程;

3,wait 当fork启动一个子进程时,子进程就有了它自己的生命周期并将独立运行,我们可以在父进程中调用wait函数让父进程等待子进程的结束;

相信介绍到这里,读者已经能够想到解决方法了:1)首先使用fork系统调用,创建子进程,2)在子进程中使用exec函数,执行需要自动重启的程序,3) 在父进程中执行wait等待子进程的结束,然后重新创建一个新的子进程。

 

使用方法:

#./portmap 需要监控的程序的路径
#args portmap 需要的参数
$ ./supervisor ./portmap  args.....

 

代码如下:

/**
 *
 * supervisor 
 *
 * author: liyangguang (liyangguang@software.ict.ac.cn)
 *
 * date: 2011-01-21 21:04:01
 *
 * changes
 * 1, execl to execv
 */
 
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
 
int
main(int argc, char **argv)
{
    int ret, i, status;
    char *child_argv[100] = {0};
    pid_t pid;
    if (argc < 2) {
 
        fprintf(stderr, "Usage:%s <exe_path> <args...>n", argv[0]);
        return -1;
    }
    for (i = 1; i < argc; ++i) {
        child_argv[i-1] = (char *)malloc(strlen(argv[i])+1);
        strncpy(child_argv[i-1], argv[i], strlen(argv[i]));
        child_argv[i-1][strlen(argv[i])] = '0';
    }
    while(1){
 
        pid = fork(); 
        if (pid == -1) {
            fprintf(stderr, "fork() error.errno:%d error:%sn", errno, strerror(errno));
            break;
        }
        if (pid == 0) {
            ret = execv(child_argv[0], (char **)child_argv);
            //ret = execl(child_argv[0], "portmap", NULL, 0);
            if (ret < 0) {
                fprintf(stderr, "execv ret:%d errno:%d error:%sn", ret, errno, strerror(errno));
                continue;
            }
            exit(0);
        }
 
        if (pid > 0) {
            pid = wait(&status);
 
            fprintf(stdout, "wait return");
        }
 
    }
 
 
    return 0;
}

shell脚本方式的代码如下:

# 函数: CheckProcess
# 功能: 检查一个进程是否存在
# 参数: $1 --- 要检查的进程名称
# 返回: 如果存在返回0, 否则返回1.
#------------------------------------------------------------------------------
CheckProcess()
{
  # 检查输入的参数是否有效
  if [ "$1" = "" ];
  then
    return 1
  fi
 
  #$PROCESS_NUM获取指定进程名的数目,为1返回0,表示正常,不为1返回1,表示有错误,需要重新启动
  PROCESS_NUM=`ps -ef | grep "$1" | grep -v "grep" | wc -l` 
  if [ $PROCESS_NUM -eq 1 ];
  then
    return 0
  else
    return 1
  fi
}
 
 
# 检查test实例是否已经存在
while [ 1 ] ; do
 CheckProcess "test"
 CheckQQ_RET=$?
 if [ $CheckQQ_RET -eq 1 ];
 then
 
# 杀死所有test进程,可换任意你需要执行的操作
 
 
  killall -9 test
  exec ./test &  
 fi
 sleep 1
done
2017-08-09 14:51:16 Poison_biting 阅读数 552
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7161 人正在学习 去看看 良许

简述:linux下面如果对异常退出或者奔溃的程序可以重启,带病运行肯定很不安全,但有时候并不失为一种短时间内有效解决的措施。主要是根据进程status、退出码以及系统的信号实现监督到是哪一种退出。练习模仿写的,望大神指教!!!(ps:每三次重启可自动发送邮件,也可查看CPU利用率)代码如下:

1:主程序代码(主要监督进程出错进行重启   watchdog.cpp)

#include "cpuuse.h"
#include "maile.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <assert.h>
#include <getopt.h>
#include <initializer_list>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <memory>
#include <pwd.h>
#include <grp.h>
#include <algorithm>

#define HAVE_SYS_PRCTL_H 


#define SUPERVISOR_URL ""
#if defined(HAVE_SYS_PRCTL_H)
#include <sys/prctl.h>
#endif


class Logger {  
 public:
  Logger(const char* basename, int logLevel)
      : basename_(basename), logLevel_(logLevel) {}

  void setLogLevel(int level) 
  { 
	  logLevel_ = level; 
  }

	template <typename... Args>
	void error(const char* fmt, Args... args) 
	{
    	if (logLevel_ >= 1) 
		{
		  std::string fmt2("%s[%d]: ");
		  fmt2 += fmt;
		  fmt2 += "\n";
		  fprintf(stderr, fmt2.c_str(), basename_.c_str(), getpid(), args...);
		  fflush(stderr);
		}
	}

	template <typename... Args>
	void info(const char* fmt, Args... args) 
	{
		if (logLevel_ >= 2) 
		{
		  std::string fmt2("%s[%d]: ");
		  fmt2 += fmt;
		  fmt2 += "\n";
		  fprintf(stdout, fmt2.c_str(), basename_.c_str(), getpid(), args...);
		  fflush(stdout);
		}
	}

private:
	  const std::string basename_;
	  int logLevel_;
};

class PidTracker 
{  
	public:
	  PidTracker();
	  ~PidTracker();

	  void setMainExe(const std::string& exe) { mainExe_ = exe; }

	  void add(int pid);
	  std::vector<int> collectAll();
	  int findMainPID(const std::string& mainPidFileHint);

	  void dump(const char* msg);

	 private:
	  std::string mainExe_;
};

PidTracker::PidTracker() 
{
	  char path[80];
	  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor", getpid());
	  int rv = mkdir(path, 0777);

	  if (rv < 0) 
	  {
		perror("PidTracker: mkdir");
	  }
}

PidTracker::~PidTracker() 
{
	  char path[80];
	  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor", getpid());
	  rmdir(path);
}

void PidTracker::add(int pid) 
{
	  char path[80];
	  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor/tasks",
			   getpid());

	  char buf[64];
	  ssize_t n = snprintf(buf, sizeof(buf), "%d", pid);

	  int fd = open(path, O_WRONLY);
	  write(fd, buf, n);
	  close(fd);
}

std::vector<int> PidTracker::collectAll() 
{
	  std::vector<int> result;

	  char path[80];
	  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor/tasks",
			   getpid());

	  std::ifstream tasksFile(path);
	  std::string line;

	  while (std::getline(tasksFile, line)) 
	  {
		result.push_back(stoi(line));
	  }

	  return result;
}

/***
 * Retrieves the parent-PID of a given process or 0 on error.
*/
static pid_t getppid(pid_t pid) 
{
	  char statfile[64];
	  snprintf(statfile, sizeof(statfile), "/proc/%d/stat", pid);
	  FILE* fp = fopen(statfile, "r");
	  if (!fp) 
		  return 0;

	  int pid0;
	  char comm[16];  // definitely below 16
	  char state;
	  int ppid;

	  fscanf(fp, "%d %s %c %d", &pid0, comm, &state, &ppid);

	  return ppid;
}

	/**
	 * Retrieves absolute path to the executable of a given PID.
	 */
static std::string getExe(pid_t pid) 
{
	  char path[11 + 16];
	  snprintf(path, sizeof(path), "/proc/%d/exe", pid);

	  char buf[4096];
	  ssize_t n = readlink(path, buf, sizeof(buf) - 1);

	  if (n > 0) 
	  {
		return std::string(buf, n);
	  } 
	  else 
	  {
		return std::string();
	  }
}

int PidTracker::findMainPID(const std::string& mainPidFileHint) 
{
	  std::vector<int> candidates;

	  if (!mainPidFileHint.empty()) 
	  {
		std::ifstream ifs(mainPidFileHint);
		std::string pids;
		ifs >> pids;
		printf("PidTracker: main-PID hint: %s\n", pids.c_str());
		int pid = std::stoi(pids);
		if (pid != 0) 
		{
		  return pid;
		}
	  }

	  for (int pid : collectAll()) 
	  {
		if (getppid(pid) == getpid()) 
		{
		  if (getExe(pid) == mainExe_) 
		  {
			candidates.push_back(pid);
		  }
		}
	  }

	  return !candidates.empty() ? candidates.front() : 0;
}

	void PidTracker::dump(const char* msg) 
	{
#if 0  
		  assert(msg && *msg);
		  printf("PID tracking dump (%s): ", msg);

		  for (int pid : collectAll()) 
		  {
			printf(" %d", pid);
		  }
		  printf("\n");
#endif
	}

	class Program 
	{  
		 public:
		  Program(Logger* logger, const std::string& exe,
				  const std::vector<std::string>& argv, const std::string& mainPidfile);
		  ~Program();

		  bool start();
		  bool restart();
		  bool resume();
		  void signal(int signo);

		  int pid() const { return pid_; }

		 private:
		  bool spawn();

		 private:
		  Logger* logger_;
		  std::string exe_;
		  std::vector<std::string> argv_;
		  std::string mainPidfile_;
		  int pid_;
		  PidTracker pidTracker_;
	};

	Program::Program(Logger* logger, const std::string& exe,
						 const std::vector<std::string>& argv,
						 const std::string& mainPidfile)
			: logger_(logger),
			  exe_(exe),
			  argv_(argv),
			  mainPidfile_(mainPidfile),
			  pid_(0),
			  pidTracker_() 
	{
		  pidTracker_.setMainExe(exe);
	}

	Program::~Program() {}

	bool Program::start() 
	{
		  return spawn();
	}

	bool Program::resume() 
	{
		  pidTracker_.dump("resume");

		  if (pid_t pid = pidTracker_.findMainPID(mainPidfile_)) 
		  {
			logger_->info("new main pid: %d", pid);
			pid_ = pid;
			return true;
		  }

		  const auto pids = pidTracker_.collectAll();
		  if (!pids.empty()) 
		  {
			pid_ = pids[0];
			return true;
		  }

		  return false;
	}

	bool Program::restart() 
	{
		  return spawn();
	}

	void Program::signal(int signo)
	{
		  // just send signal to PID
		  kill(pid_, signo);
	}

	bool Program::spawn() 
	{
	  logger_->info("starting program (%s)...", exe_.c_str());

	  pid_t pid = fork();

	  if (pid < 0) 
	  {
		logger_->error("fork failed. %s", strerror(errno));
		return false;
	  } 
	  else if (pid > 0) 
	  {  // parent
		pid_ = pid;
		pidTracker_.add(pid);
		logger_->info("child pid is %d", pid);
		return true;
	  } 
	  else 
	  {  // child
		std::vector<char*> argv;

		for (const std::string& arg : argv_) 
		{
		  argv.push_back(const_cast<char*>(arg.c_str()));
		}
		argv.push_back(nullptr);

		execvp(exe_.c_str(), argv.data());
		logger_->error("execvp failed. %s", strerror(errno));
		abort();
	  }
}

class Supervisor { 
	 public:
	  Supervisor();
	  ~Supervisor();

	  int run(int argc, char* argv[]);

	  static Supervisor* self() { return self_; }

	 private:
	  bool isExitSuccess(int code) const;
	  bool isExitSuccess() const;
	  bool parseArgs(int argc, char* argv[]);
	  void printHelp();
	  bool restart();
	  static void sighandler(int signum);


	  Logger* logger() { return &logger_; }

	 private:
	  static Supervisor* self_;
	  Logger logger_;
	  std::unique_ptr<Program> program_;
	  std::string pidfile_;
	  std::string mainPidfile_;
	  int restartCount_;       //!< number of actual restarts so far
	  int restartDelay_;       //!< current restart delay
	  int restartDelayLimit_;  //!< restart delay limit

	  int restartOnError_;  //!< restart app on normal exit but code != 0
	  int restartOnCrash_;  //!< restart app on SIGSEGV
	  bool fork_;
	  int exitCode_;
	  std::vector<int> successExitCodes_;
};

Supervisor* Supervisor::self_ = nullptr;

Supervisor::Supervisor()
		: logger_("supervisor", 2),
		  program_(nullptr),
		  pidfile_(),
		  mainPidfile_(),
		  restartCount_(0),        // number of actual restarts
		  restartDelay_(0),        // do not wait during restarts
		  restartDelayLimit_(30),  // exponential backup delay cap
		  restartOnError_(false),
		  restartOnCrash_(false),
		  fork_(false),
		  exitCode_(0),
		  successExitCodes_() 
	{
	  assert(self_ == nullptr);
	  self_ = this;
	  successExitCodes_.push_back(EXIT_SUCCESS);
	}

	Supervisor::~Supervisor() 
	{
	  self_ = nullptr;

	  if (!pidfile_.empty()) 
	  {
		unlink(pidfile_.c_str());
	  }
	}

	bool Supervisor::parseArgs(int argc, char* argv[])    //解析命令函数
	{
	  if (argc <= 1) 
	  {
		printHelp();
		return false;
	  }

	  struct option opts[] = {
		  					  {"fork",no_argument,nullptr,'f'},
							  {"delay-limit", required_argument, nullptr, 'l'},
							  {"restart-on-error", no_argument, nullptr, 'e'},
							  {"restart-on-crash", no_argument, nullptr, 'c'},
							  {0, 0, 0, 0}
							  };

	  int logLevel = 2;

	  for (;;) 
	  {
		int long_index = 0;
		switch (getopt_long(argc, argv, "fp:l:fec", opts, &long_index))   //命令行解析函数,前面必须要有一个option的结构体
		{
			case 'f':
				fork_= true;
				break;
		  	case 'l':
			// TODO: ensure optarg is a number
				restartDelayLimit_ = atoi(optarg);
        		break;
      		case 'e':
        		restartOnError_ = true;
        		break;
      		case 'c':
        		restartOnCrash_ = true;
        		break;
      		case 0:  // long option with (val!=nullptr && flag=0)
        		break;
      		case -1: {
        // EOF - everything parsed.
        		if (optind == argc) 
				{
          			logger()->error("no program path given");
          			return false;
        		}

        std::vector<std::string> args;
        while (optind < argc) 
		{
          args.push_back(argv[optind++]);
        }

        if (args[0].empty() || args[0][0] != '/') 
		{
          logger()->error("program path must be absolute.");
          return false;
        }

        if (getuid() && getuid()) 
		{
          logger()->error("Must run as (setuid) root. Please fix permissions.");
          return false;
        }

        if (fork_) 
		{
          int rv = daemon(1, 1);   //成功为0  失败为-1
          if (rv < 0) 
		  {
            logger()->error("Could not daemonize into background. %s",
                            strerror(errno));

            return false;
          }
        }

        logger_.setLogLevel(logLevel);

        program_.reset(new Program(logger(), args[0], args, mainPidfile_));

        auto signals = {SIGINT,  SIGQUIT, SIGTERM, SIGCONT,
                        SIGUSR1, SIGUSR2, SIGTTIN, SIGTTOU};

        for (int sig : signals) 
		{
          signal(sig, &Supervisor::sighandler);
        }

        return true;
      }
      case '?':  // ambiguous match / unknown arg
      default:
        return false;
    }
  }
  return true;
}


void Supervisor::printHelp() 
{
  printf(
      "watchdog: process supervising tool.\n"

	  "  -f,--fork              daemon process\n"
      "  -l,--delay-limit=N     max sleep time(no more than 30s)\n"
      "  -e,--restart-on-error  restart exitcode!=0\n"
      "  -c,--restart-on-crash  restart crash (SIGSEGV)\n"
      "\n"
      "Examples:\n"
      "    ./a.out -c /home/wyf1/linux_wdog/Test/test\n"
      "    ./a.out -e /home/wyf1/linux_wdog/Test/ll\n"
      "\n");
}

int Supervisor::run(int argc, char* argv[])  //运行
{
  if (!parseArgs(argc, argv))  // 命令解析为false则失败退出
  {
    return EXIT_FAILURE;
  }

  if (!pidfile_.empty())    //判断pid字符串是否为空
  {
    logger()->info("writing watchdog-PID %d to %s", getpid(),
                   pidfile_.c_str());

    std::ofstream fs(pidfile_, std::ios_base::out | std::ios_base::trunc);    //读操作,从存储设备到内存
    fs << getpid() << std::endl; 
  }

  program_->start();  //程序启动
  for (;;) 
  {
	cpuuse();   //CPU使用情况
    int status = 0;
    pid_t pid = waitpid(-1, &status, 0);
    if (pid < 0) 
	{
      perror("waitpid");
      return EXIT_FAILURE;
    }

    if (pid != program_->pid()) 
	{
      logger()->info("Reaping child PID %d", pid);
      continue;
    }

    if (WIFEXITED(status))    //判断子进程是否正常结束(非0就是正常) 
	{

		//cout<<WIFEXITED(status)<<endl;
      exitCode_ = WEXITSTATUS(status);   //子进程exit()退出码

      logger()->info("program PID %d terminated normally with exit code %d",
                     program_->pid(), exitCode_);

      if (program_->resume()) 
	  {
        logger()->info("reattaching to child PID %d.", program_->pid());
        continue;
      }

      if (!isExitSuccess() && restartOnError_) {
        logger()->info("restarting due to error code %d", exitCode_);

        if (restart())
		{
			continue;
		}
      }

      logger()->info("shutting down watchdog with application exit code %d",
                     exitCode_);
		//cout<<WIFEXITED(status)<<endl;
      return exitCode_;
    }
	//cout<<WIFEXITED(status)<<endl;

    if (WIFSIGNALED(status)) 
	{   //如果子进程是因为信号而终止的 这个值是true
      int sig = WTERMSIG(status); //获取子进程因信号终止的代码
      logger()->info("Child %d terminated with signal '%s' (%d)",
                     program_->pid(), strsignal(sig), sig);     //strsignal()将信号值转换为描述信号的字符串

      // do only attempt to restart if it's none of those signals.
      static const int sigs[] = {SIGTERM, SIGINT, SIGQUIT};   //程序正常退出/通知前台进程组终止进程/产生core文件,收到一个程序错误信号
      bool softTerminate =
          std::find(std::begin(sigs), std::end(sigs), sig) == std::end(sigs);  //判断是否为SIGQUIT信号
	  bool sTerminate = (SIGFPE==sig);
	  bool ssTerminate= (SIGILL==sig);
	  bool st=(SIGSEGV==sig);
      if ((softTerminate && restartOnCrash_ && restart())||(sTerminate && restartOnCrash_ && restart())||(ssTerminate && restartOnCrash_&& restart())||(st&&restartOnCrash_ && restart())) 
		  continue;

      return exitCode_;
    }


    if (restart())
	{
		continue;
	}

    return exitCode_;
  }
}

bool Supervisor::isExitSuccess(int value) const  
{
  for (int code: successExitCodes_)
    if (value == code)
      return true;

  return false;
}

bool Supervisor::isExitSuccess() const 
{
  return isExitSuccess(exitCode_);
}

bool Supervisor::restart() 
{
  if (restartDelay_) 
  {
    logger()->info("restart is sleeping for %d seconds\n", restartDelay_);
    sleep(restartDelay_);

    // exponential backoff for the next restart
    restartDelay_ = std::min(restartDelay_ << 1, restartDelayLimit_);
  } 
  else 
  {
    restartDelay_ = 1;
	cout<<endl;
  }

  restartCount_++;
  if(restartCount_%3==0)
  {
	  run_mail();
  }
  return program_->restart();
}

void Supervisor::sighandler(int signum)  //****
{
  if (self()->program_->pid()) 
  {
    self()->logger()->info(
        "Signal '%s' (%d) received. Forwarding to child PID %d.",
        strsignal(signum), signum, self()->program_->pid());

    // forward to child process
    self()->program_->signal(signum);
  }
}

int main(int argc, char* argv[]) 
{
  Supervisor supervisor;
  return supervisor.run(argc, argv);
}
2:发送邮件代码段(maile.h)

#pragma once
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h>
#include <string>
#include <fstream>

#define FAILED					0x00000001
#define YES						0x00000002
#define NO						0x00000003

#define PARAM_INCORRECT			0x00000010
#define CREATE_SOCKET_FAILED	0x00000012
#define CONNECT_SERVER_FAILED	0x00000013
#define CHANGE_URL_TO_IP_FAILED	0x00000014

class CAutoMail
{
public:
	CAutoMail();
	virtual ~CAutoMail();

public:
	bool init();
	void uninit();
	bool send_mail();

private:
	bool init_socket();
	void init_mail_info();
	bool base64(wstring data, const char *dst_file);
	void get_time(char *time);
	void send_mail_head(ofstream &ofs);
	void send_mail_data(ofstream &ofs);
	
public:
	unsigned int get_error_no();

private:
	wstring m_str_src_mail_p; // sender in plaintext
	wstring m_str_src_mail_c; // sender in ciphertext
	
	wstring m_str_dst_mail_p; // receiver in plaintext
	wstring m_str_dst_mail_c; // receiver in ciphertext
	
	wstring m_str_pwd_p;	// password in plaintext
	wstring m_str_pwd_c;	// password in ciphertext

	wstring m_str_title; // title of email
	wstring m_str_data; // content of email

	ofstream m_ofs_log;

	wstring m_str_email_server;
	unsigned short m_ns_server_port;
private:
	int m_socket_server;
	struct sockaddr_in m_sockaddr_server;
private:
	const static wchar_t *WSTR_DEFAULT_TITLE;
	const static char *STR_TMP_FILE;
	const static char *STR_BASE_FILE;
	static unsigned int ERROR_NUMBER;
	const static int BUF_LEN;
	const static char *STR_LOG_FILE;
	const static char *STR_EMAIL_CONF_FILE;
	const static char *STR_CODE;
};


const char *CAutoMail::STR_TMP_FILE = "base.tmp";
const char *CAutoMail::STR_BASE_FILE = "base.conf";
const char *CAutoMail::STR_LOG_FILE = "info.log";
const char *CAutoMail::STR_EMAIL_CONF_FILE = "email.conf";
unsigned int CAutoMail::ERROR_NUMBER = 0x00000001;
const int CAutoMail::BUF_LEN = 256;
const char *CAutoMail::STR_CODE = "UTF-8";

CAutoMail::CAutoMail() 
{
	/*
	 * set code for multi-char language, such as Chinese
	*/
	locale loc("zh_CN.UTF-8");
    locale::global( loc );
}

CAutoMail::~CAutoMail() {}

void CAutoMail::init_mail_info()
{
	wchar_t _buf[BUF_LEN] = {0};
	wifstream _ifs(STR_EMAIL_CONF_FILE);
	int _iPrefixLen = 4; // length of prefix per line, such as src=xxx@gmail.com, the prefix is "src="
	wstring _str_pre;
	
	while (!_ifs.eof()) 
	{
		memset(_buf, 0, sizeof(_buf));
		_ifs.getline(_buf, sizeof(_buf));
		_str_pre = _buf;
    	_str_pre = _str_pre.substr(0, _iPrefixLen); // get the prefix

		if (wcscmp(_str_pre.data(), L"src=") == 0) // get sender mail address
		{
			m_str_src_mail_p = _buf;
			m_str_src_mail_p = m_str_src_mail_p.substr(_iPrefixLen);
		}
		
		else if (wcscmp(_str_pre.data(), L"dst=") == 0) // get receiver mail address 
		{
			m_str_dst_mail_p = _buf;
			m_str_dst_mail_p = m_str_dst_mail_p.substr(_iPrefixLen);
		}
		else if (wcscmp(_str_pre.data(), L"svr=") == 0) // get the mail server, like "smtp.163.com"
		{
			m_str_email_server = _buf; 
			m_str_email_server = m_str_email_server.substr(_iPrefixLen);
		}
		else if (wcscmp(_str_pre.data(), L"prt=") == 0) // get the server port
		{
			char _buf_tmp[16] = {0};
			wstring _str(_buf);
			_str = _str.substr(_iPrefixLen);
			wcstombs(_buf_tmp, _str.data(), _iPrefixLen+1);
			m_ns_server_port = atoi(_buf_tmp);
		}
		else if (wcscmp(_str_pre.data(), L"psd=") == 0) // get sender email password
		{
			m_str_pwd_p = _buf;
			m_str_pwd_p = m_str_pwd_p.substr(_iPrefixLen);
		}
		else if (wcscmp(_str_pre.data(), L"dat=") == 0) // get the content of email
		{
			m_str_data = _buf;
			m_str_data = m_str_data.substr(_iPrefixLen);			
		}
		else if (wcscmp(_str_pre.data(), L"tit=") == 0) // get the title of email
		{
			m_str_title = _buf;
			m_str_title = m_str_title.substr(_iPrefixLen);
		}
		else 
		{
			m_str_data += L"\n";
			m_str_data += _buf;
		}
	}
	_ifs.close();
}

unsigned int CAutoMail::get_error_no()
{
	return ERROR_NUMBER;
}


bool CAutoMail::init()
{
		
	init_mail_info();

	if (!init_socket())
		return false;

	return true;
}

void CAutoMail::uninit()
{
	shutdown(m_socket_server, SHUT_RDWR);
	close(m_socket_server);
	char _buf[BUF_LEN] = {0};
	
	memset(_buf, 0, sizeof(_buf));
	sprintf(_buf, "rm -f %s", STR_BASE_FILE);
	system(_buf);
	
	memset(_buf, 0, sizeof(_buf));
	sprintf(_buf, "rm -f %s", STR_TMP_FILE);
	system(_buf);
}

bool CAutoMail::init_socket()
{
	char _buf_svr[BUF_LEN] = {0};
	wcstombs(_buf_svr, m_str_email_server.data(), m_str_email_server.length()+1);
	hostent *host_server = gethostbyname(_buf_svr);

	if (host_server == NULL)
	{
		ERROR_NUMBER = CHANGE_URL_TO_IP_FAILED;
		return false;
	}

	m_socket_server = socket(AF_INET,SOCK_STREAM,0);
	if (m_socket_server < 0)
	{
		ERROR_NUMBER = CREATE_SOCKET_FAILED;
		return false;
	}

	m_sockaddr_server.sin_family = AF_INET;
 	m_sockaddr_server.sin_port = htons(m_ns_server_port);
	m_sockaddr_server.sin_addr = *((struct in_addr *)host_server->h_addr);
	memset(&(m_sockaddr_server.sin_zero), 0, 8) ;

	return true;
}

bool CAutoMail::base64(wstring data, const char *dst_file)
{
	if (dst_file == NULL)
	{
		ERROR_NUMBER = PARAM_INCORRECT;
		return false;
	}

	wofstream _ofs(STR_TMP_FILE); // create temp file to store data
	_ofs << data.data();
	_ofs.close();
	
	char buf[BUF_LEN] = {0}; // to encode data with base64 by shell
	sprintf(buf,"base64 %s >> %s", STR_TMP_FILE, dst_file);
	system(buf);

	memset(buf, 0, sizeof(buf));
	sprintf(buf, "rm -f %s", STR_TMP_FILE);
	system(buf);

	return true;
}

void CAutoMail::get_time(char *time_buf)
{
	if (time_buf == NULL)
		return;
	time_t tt = time(NULL);
	struct tm *time_now = localtime(&tt);
	sprintf(time_buf, "%d-%d-%d-%d:%d:%d", time_now->tm_year+1900, time_now->tm_mon+1, time_now->tm_mday, time_now->tm_hour, 
	        time_now->tm_min, time_now->tm_sec);
}

void CAutoMail::send_mail_head(ofstream &ofs)
{
	char buf_send[BUF_LEN] = {0};
	char buf_recv[BUF_LEN] = {0};
	char time[BUF_LEN] = {0};
	int reval = 0;

	sprintf(buf_send, "EHLO %S\r\n", m_str_src_mail_p.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0); // send with src mail
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(time);
	ofs << time << ": " << buf_recv;

	memset(buf_send, 0, sizeof(buf_send));
	memset(buf_recv, 0, sizeof(buf_recv));
	sprintf(buf_send,"AUTH LOGIN\r\n");
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(time);
	ofs << time << ": " << buf_recv;

	memset(buf_send, 0, sizeof(buf_send));
	memset(buf_recv, 0, sizeof(buf_recv));
	sprintf(buf_send, "%S\r\n", m_str_src_mail_c.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0); // send username, after encode with base64
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(time);
	ofs << time << ": " << buf_recv;

	memset(buf_send, 0, sizeof(buf_send));
	memset(buf_recv, 0, sizeof(buf_recv));
	sprintf(buf_send, "%S\r\n", m_str_pwd_c.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0); // send password, after encode with base64
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(time);
	ofs << time << ": " << buf_recv;
}

void CAutoMail::send_mail_data(ofstream &ofs)
{
	char buf_send[BUF_LEN] = {0};
	char buf_recv[BUF_LEN] = {0};
	char buf_time[BUF_LEN] = {0};
	int reval = 0;

	sprintf(buf_send, "MAIL FROM: <%S>\r\n", m_str_src_mail_p.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(buf_time);
	ofs << buf_time << ": " << buf_recv;

	memset(buf_recv, 0, sizeof(buf_recv));
	memset(buf_time, 0, sizeof(buf_time));
	memset(buf_send, 0, sizeof(buf_send));
	sprintf(buf_send, "RCPT TO: <%S>\r\n", m_str_dst_mail_p.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(buf_time);
	ofs << buf_time << ": " << buf_recv;

	memset(buf_recv, 0, sizeof(buf_recv));
	memset(buf_time, 0, sizeof(buf_time));
	memset(buf_send, 0, sizeof(buf_send));
	sprintf(buf_send, "DATA\r\n");
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(buf_time);
	ofs << buf_time << ": " << buf_recv;

	memset(buf_send, 0, sizeof(buf_send));

	sprintf(buf_send, "FROM: %S\r\nTO: %S\r\n", m_str_src_mail_p.data(), m_str_dst_mail_p.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	
	memset(buf_send, 0, sizeof(buf_send));
	sprintf(buf_send, "SUBJECT: %S\r\n", m_str_title.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0);

	memset(buf_send, 0, sizeof(buf_send));
	sprintf(buf_send, "Content-type: text/plain;charset=%s\r\n", STR_CODE);
	send(m_socket_server, buf_send, strlen(buf_send), 0);

	memset(buf_send, 0, sizeof(buf_send));
	sprintf(buf_send, "\r\n%S\r\n", m_str_data.data());
	send(m_socket_server, buf_send, strlen(buf_send), 0);

	memset(buf_send, 0, sizeof(buf_send));
	memset(buf_recv, 0, sizeof(buf_recv));
	sprintf(buf_send, "\r\n.\r\n");
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(buf_time);
	ofs << buf_time << ": " << buf_recv;

	memset(buf_send, 0, sizeof(buf_send));
	memset(buf_recv, 0, sizeof(buf_recv));
	sprintf(buf_send, "QUIT\r\n");
	send(m_socket_server, buf_send, strlen(buf_send), 0);
	recv(m_socket_server, buf_recv, sizeof(buf_recv), 0);
	get_time(buf_time);
	ofs << buf_time << ": " << buf_recv;
}

bool CAutoMail::send_mail()
{
	m_str_src_mail_p;
	m_str_pwd_p;
	m_str_dst_mail_p;
	
	base64(m_str_src_mail_p, STR_BASE_FILE);
	base64(m_str_pwd_p, STR_BASE_FILE);
	base64(m_str_dst_mail_p, STR_BASE_FILE);
	

	char buf_send[BUF_LEN] = {0};
	char buf_recv[BUF_LEN] = {0};
	char buf_time[BUF_LEN] = {0};

	ofstream ofs(STR_LOG_FILE);
	wchar_t _buf_info[BUF_LEN] = {0};
	char buf[BUF_LEN] = {0};
	
	wifstream ifs(STR_BASE_FILE);
	ifs.getline(_buf_info,sizeof(_buf_info));
	m_str_src_mail_c = _buf_info;
	memset(_buf_info, 0, sizeof(_buf_info));
	ifs.getline(_buf_info,sizeof( _buf_info));
	m_str_pwd_c = _buf_info;
	memset(_buf_info, 0, sizeof( _buf_info));
	ifs.getline(_buf_info,sizeof(_buf_info));
	m_str_dst_mail_c = _buf_info;
	ifs.close();
	
	int reval = connect(m_socket_server, (struct sockaddr*)&m_sockaddr_server, sizeof(struct sockaddr));
	// connect to mail server
	if (reval != 0)
	{
		ERROR_NUMBER = CONNECT_SERVER_FAILED;
		uninit();
		return false;
	}

	recv(m_socket_server, buf, sizeof(buf), 0); // get welcome message from server
	memset (buf_time, 0, sizeof(buf_time));
	get_time(buf_time);
	ofs << buf_time << ": " << buf;
	
	send_mail_head(ofs);
	send_mail_data(ofs);
	
	ofs.close();
	cout << "send completed." << endl;
	return true;
}

int run_mail()
{
	CAutoMail automail;
	automail.init();
	if(!automail.send_mail())
		cout<<automail.get_error_no()<<endl;
	automail.uninit();
	return 0;
}
3:邮件配置文件(email.conf)
dst=接收方邮箱

src=发送方邮箱

svr=smtp.163.com

prt=25

psd=第三方授权密码

tit=标题

dat=内容
4:cpu利用率代码段(cpuuse.h)
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

typedef struct         //定义一个cpu occupy的结构体
{
	char name[20];      //定义一个char类型的数组名name有20个元素
	unsigned int user; //定义一个无符号的int类型的user
	unsigned int nice; //定义一个无符号的int类型的nice
	unsigned int system;//定义一个无符号的int类型的system
	unsigned int idle; //定义一个无符号的int类型的idle
}CPU_OCCUPY;


double cal_cpuoccupy(CPU_OCCUPY *o, CPU_OCCUPY *n)
{
	unsigned int od, nd;
	unsigned int id, sd;
	double cpu_use = 0;
	double st,tol;

	od = (unsigned int)(o->user + o->nice + o->system + o->idle);//第一次(用户+优先级+系统+空闲)的时间再赋给od
	nd = (unsigned int)(n->user + n->nice + n->system + n->idle);//第二次(用户+优先级+系统+空闲)的时间再赋给od

	id = (unsigned int)(n->user - o->user);    //用户第一次和第二次的时间之差再赋给id
	sd = (unsigned int)(n->system - o->system);//系统第一次和第二次的时间之差再赋给sd
	st=sd+id;
	tol=nd-od;
    printf("%.2f,%.2f\n",st,tol);
	if (tol != 0)
		cpu_use = (st * 100) / tol; //((用户+系统)乖100)除(第一次和第二次的时间差)再赋给g_cpu_used
	else 
		cpu_use = 0;
	//printf("cpu: %.2f\%\n", cpu_use);
	return cpu_use;
}

void get_cpuoccupy(CPU_OCCUPY *cpust) //对无类型get函数含有一个形参结构体类弄的指针O
{
	FILE *fd;
	int n;
	char buff[256];
	CPU_OCCUPY *cpu_occupy;
	cpu_occupy = cpust;

	fd = fopen("/proc/stat", "r");
	fgets(buff, sizeof(buff), fd);

	sscanf(buff, "%s %u %u %u %u", cpu_occupy->name, &cpu_occupy->user, &cpu_occupy->nice, &cpu_occupy->system, &cpu_occupy->idle);
	//printf("name = %s, user = %u, nice = %u, system = %u , idle = %u \n", cpu_occupy->name, cpu_occupy->user, cpu_occupy->nice, cpu_occupy->system, cpu_occupy->idle);

	fclose(fd);
}

int cpuuse()
{
	CPU_OCCUPY cpu_stat1;
	CPU_OCCUPY cpu_stat2;
	double cpu;
	//第一次获取cpu使用情况
	//printf("===============================cpu use================================\n");
	get_cpuoccupy((CPU_OCCUPY *)&cpu_stat1);
	sleep(5);

	//第二次获取cpu使用情况
	get_cpuoccupy((CPU_OCCUPY *)&cpu_stat2);

	//计算cpu使用率
	cpu = cal_cpuoccupy((CPU_OCCUPY *)&cpu_stat1, (CPU_OCCUPY *)&cpu_stat2);
	printf("cpu use = %.2f\%\n", cpu);
	//printf("======================================================================\n");

	return 0;
}
5:Makefile文件

CC=g++ -std=c++11

FLAG=-D DEBUG



watchdog:watchdog.o
	
	$(CC) $(FLAG) watchdog.o


watchdog.o:watchdog.cpp cpuuse.h maile.h 
	
	$(CC) $(FLAG) -c watchdog.cpp -o watchdog.o

clear:
	
-rm -f *.o
	
-rm -f .so
	
-rm -f *.gch






2013-09-29 11:19:24 dgyanyong 阅读数 5696
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7161 人正在学习 去看看 良许

//使用ACE监控启动进程,进程崩溃后自动重启(windows/linux通用)

原理:

监护程序使用子进程的方式启动各个进程,

子进程退出时,监护程序能够得到相应的退出信号,

从而在子进程退出后,在重新启动相应的子进程。

//----------------------------------------------------------
//配置文件ProcessManager.conf格式
//./PROCESS_MANAGER 1
//./PROCESS_MANAGER 2
//----------------------------------------------------------

// main.cpp

// main.cpp
#include "CProcessManager.h"
int main(int argc, char *argv[])
{
	// Running as a child for test.
	if (argc > 1)
	{
		ACE_OS::sleep(10);
		return 0;
	}
	// set output log file
	ACE_OS::setprogname("ProcessManager");
	ACE_Date_Time tvTime(ACE_OS::gettimeofday());
	char szLogFileName[256];
	memset(szLogFileName, 0, sizeof(szLogFileName));
	snprintf(szLogFileName, sizeof(szLogFileName), "log/%s_%04d%02d%02d_%02d%02d%02d.log", 
		ACE_OS::getprogname(), 
		(int)tvTime.year(), (int)tvTime.month(),  (int)tvTime.day(), 
		(int)tvTime.hour(), (int)tvTime.minute(), (int)tvTime.second());

	ACE_OSTREAM_TYPE *pLogOutput = new ofstream(szLogFileName);
	ACE_LOG_MSG->msg_ostream(pLogOutput, true);
	ACE_LOG_MSG->set_flags(ACE_Log_Msg::OSTREAM);
	// Prepends timestamp and message priority to each message
	ACE_LOG_MSG->set_flags(ACE_Log_Msg::VERBOSE_LITE);
	//ACE_LOG_MSG->clr_flags(ACE_Log_Msg::STDERR);

	ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager START---.\n")));
	int nRet = 0;
	CProcessManager *pProcMng = new CProcessManager();
	// 启动进程监控
	nRet = pProcMng->ProcessMonitor();
	if(nRet != 0)
	{
		ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: ---ProcessMonitor Error---\n")));
	}
	delete pProcMng;
	ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager STOP---.\n")));
	ACE_LOG_MSG->clr_flags(ACE_Log_Msg::OSTREAM);
	delete pLogOutput;
	return 0;
}


 

头文件CProcessManager.h

类的定义如下

//CProcessManager.h
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <map>
using namespace std;

#include "ace/OS.h"
#include "ace/streams.h"
#include "ace/Log_Msg.h"
#include "ace/Date_Time.h"
#include "ace/Event_Handler.h"
#include "ace/Reactor.h"
#include "ace/Process_Manager.h"

// 进程监控,进程崩溃后,自动重新启动进程
class CProcessManager
{
public:
	CProcessManager(){};
	virtual ~CProcessManager(){};
	// 从配置文件读取进程列表信息
	virtual int ReadConfigProcessInfo(char *pFileName);
	// 启动进程,并进行进程监控,进程崩溃后,自动重新启动进程
	virtual int ProcessMonitor();

private:
	vector<string> m_vConfigProcessInfo;       // 进程列表信息
};

// 回调事件,程序退出后,执行handle_exit函数
class CProcessExitHandler: public ACE_Event_Handler
{
public:
	CProcessExitHandler(){};
	virtual ~CProcessExitHandler(){};
	// 程序退出后,执行该函数
	virtual int handle_exit(ACE_Process* process);
};


//CProcessManager.cpp类中函数的实现

//实现自动重新启动进程

//CProcessManager.cpp
#include "CProcessManager.h"

ACE_Process_Manager *g_pPM;             // 进程管理
map<string, pid_t> g_mapProcessInfo;    // 进程ID管理列表

// 读取进程列表配置文件
int CProcessManager::ReadConfigProcessInfo(char *pFileName)
{
	char *pTemp = NULL;
	char szTemp[1024];
	string strTemp = "";
	if(NULL == pFileName) 
	{
		ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: Parameter FileName is null.\n")));
		return -1;
	}
	// 文件格式
	//./PROCESS_MANAGER 1
	//./PROCESS_MANAGER 2
	// 打开进程列表配置文件
	FILE *fp = fopen(pFileName, "r");
	if(NULL == fp)
	{
		ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: file open error.[%s]\n"), pFileName));
		return -2;
	}
	// 循环读取进程列表配置文件
	while(1)
	{
		memset(szTemp, 0, sizeof(szTemp));
		pTemp = fgets(szTemp, sizeof(szTemp), fp);
		if(NULL == pTemp)
		{
			break;
		}
		// 去掉注释
		if(szTemp[0] == '#')
		{
			continue;
		}
		strTemp = szTemp;
		if(strTemp.length() == 0)
		{
			continue;
		}
		// 去掉回车换行
		if(strTemp[strTemp.length() - 1] == '\n')
		{
			strTemp[strTemp.length() - 1] = 0;
		}
		if(strTemp.length() == 0)
		{
			continue;
		}
		if(strTemp[strTemp.length() - 1] == '\r')
		{
			strTemp[strTemp.length() - 1] = 0;
		}
		if(strTemp.length() == 0)
		{
			continue;
		}
		// 把读取的进程信息放到[进程列表信息]全局变量
		m_vConfigProcessInfo.push_back(strTemp);
	}
	// 关闭进程列表配置文件
	fclose(fp);
	// [进程列表信息]不应该为0
	if(m_vConfigProcessInfo.size() == 0)
	{
		ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: Process list is null.[%s]\n"), pFileName));
		return -3;
	}
	return 0;
}

// 进程监控
// 根据配置文件启动进程,并注册进程退出时回调函数
int CProcessManager::ProcessMonitor()
{
	int nRet = 0;
	vector<string>::iterator itrConfig;
	string strStartProcess;

	m_vConfigProcessInfo.clear();

	// 读取进程列表配置文件
	nRet = ReadConfigProcessInfo("ProcessManager.conf");
	if(nRet != 0)
	{
		ACE_DEBUG((LM_ERROR, 
			ACE_TEXT("[%N:%l]: ReadConfigProcessInfo[%s] error.\n"), "ProcessManager.conf"));
		return -1;
	}

	// Instantiate a process manager with space for 100 processes.
	g_pPM = new ACE_Process_Manager(ACE_Process_Manager::DEFAULT_SIZE, ACE_Reactor::instance());
	CProcessExitHandler procExitHandler;
	// 循环配置进程列表,启动进程
	for(itrConfig = m_vConfigProcessInfo.begin(); itrConfig != m_vConfigProcessInfo.end(); ++itrConfig)
	{
		strStartProcess = *itrConfig;
		// 启动进程
		ACE_Process_Options options;
		options.command_line(strStartProcess.c_str());
		pid_t pid = g_pPM->spawn(options);
		// 启动进程失败
		if (pid == ACE_INVALID_PID)
		{
			ACE_DEBUG((LM_ERROR, 
				ACE_TEXT("[%N:%l]: start a child process success(%d)%s\n"), 
				pid, strStartProcess.c_str()));
			return -1;
		}
		ACE_DEBUG((LM_INFO, 
			ACE_TEXT("[%N:%l]: start a child process success(%d)%s\n"), 
			pid, strStartProcess.c_str()));
		// 注册回调(进程退出时,调用该回调)
		g_pPM->register_handler(&procExitHandler, pid);
		// 添加启动成功的进程到进程ID管理列表
		g_mapProcessInfo[strStartProcess] = pid;
		ACE_OS::sleep(1);
	}

	// Run the reactor event loop waiting for events to occur.
	ACE_Reactor::instance()->run_reactor_event_loop();
	//ACE_Reactor::instance()->end_reactor_event_loop();
	return 0;
}

// 进程退出回调函数
// 程序退出后,执行该函数,重新启动进程
int CProcessExitHandler::handle_exit(ACE_Process* process)
{
	map<string, pid_t>::iterator itrProcess;

	ACE_DEBUG((LM_INFO,
		ACE_TEXT("[%N:%l]: Process %d exited with exit code %d\n"),
		process->getpid (), process->return_value()));

	// 循环进程ID管理列表,根据进程ID找到退出的进程,重新启动进程
	for(itrProcess = g_mapProcessInfo.begin(); itrProcess != g_mapProcessInfo.end(); ++itrProcess)
	{
		// 根据进程ID,查找进程名
		if(itrProcess->second == process->getpid())
		{
			// 重新启动进程
			ACE_Process_Options options;
			options.command_line(itrProcess->first.c_str());
			pid_t pid = g_pPM->spawn(options);
			// 重新启动进程失败
			if (pid == ACE_INVALID_PID)
			{
				ACE_DEBUG((LM_ERROR, 
					ACE_TEXT("[%N:%l]: restart a child process error(%d)%s\n"), 
					pid, itrProcess->first.c_str()));
				return -1;
			}
			ACE_DEBUG((LM_INFO, 
				ACE_TEXT("[%N:%l]: restart a child process success(%d)%s\n"), 
				pid, itrProcess->first.c_str()));
			// 注册回调(进程退出时,调用该回调)
			g_pPM->register_handler(this, pid);
			// 添加启动成功的进程到进程ID管理列表
			itrProcess->second = pid;
			break;
		}
	}
	return 0;
}


 

2015-10-29 18:36:36 flyeagle022 阅读数 2011
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7161 人正在学习 去看看 良许

一、成品经过长期的自动化测试后,发现偶然出现主进程异常退出的现象,于是受开发者的委托,用SHELL写一段监视程序,要求如下:
主进程退出后,自动重启这个主进程。
主进程程序状态为Z时,重启该主进程。
主进程的CPU负载超过95%时,3分钟内持续在高位运行时,重启应用程序。

直接上代码。

#!/bin/sh
##################################
#Author : 154353294@qq.com
#Date   : 2015-10-1
#Funtion: Monitor MainProcess's status,
#         IF the status of MainProcess process is Z ,then reboot system;
#         IF the MainProcess process exit abnormally,then reboot application;
#         IF the CPU usage of MainProcess process above 95% duration 3mins, then reboot applicaion.
#         The log of shell output to current directory named HealthMonitor_YYYYMMDDHHMMSS.log.
##################################
var=$0
LOGFILE=${var%%.sh}_`date "+%Y%m%d%H%M%S"`.log
echo "`date "+%Y-%m-%d %H:%M:%S"`"#"Start " > $LOGFILE
sec=3
t_start=0
t_perCurrent=0
t_current=0
total=0
MaxTimes=60 ##3*60=180s
#获取主进程的PID,内存使用率,CPU使用率,以及名称。
eval $(top -n 1| grep "MainProcess" | grep -v grep | awk  {'printf("mainPID=%s;myStatus=%s;memInfo=%s;cpuRatio=%s;pName=%s\n",$1,$4,$5,$7,$8)'})
echo `date "+%Y-%m-%d %H:%M:%S"`"#"$mainPID $myStatus  ${memInfo%%m}   ${cpuRatio%%%} $pName >> $LOGFILE

while [ true ]
do
while [  -n "$pName" ] ##MainProcess exist
    do
#       echo "`date "+%Y-%m-%d %H:%M:%S"` ####" >> $LOGFILE
        sleep $sec
        ####You must initialize them again!!!!!
        mainPID=""
        myStatus=""
        memInfo=""
        cpuRatio=""
        pName=""
        eval $(top -n 1| grep "MainProcess" | grep -v grep | awk  {'printf("mainPID=%s;myStatus=%s;memInfo=%s;cpuRatio=%s;pName=%s\n",$1,$4,$5,$7,$8)'})
            if [  ${cpuRatio%%%} -gt 95 ]; then
            #3分钟内持续负载都在95%以上的处理
#           echo  `date "+%Y-%m-%d %H:%M:%S"`"#"Cpu Usage  High: $mainPID $myStatus  ${memInfo%%m}   ${cpuRatio%%%} $pName >> $LOGFILE
            if [ $total -eq 0 ]; then
               t_start=$(date +%s) ### set first time to Seconds
               total=$(($total+1))
               t_perCurrent=$t_start
            else 
                    t_current=$(date +%s) ### set current time to Seconds

               if [ $total -ge $MaxTimes ]; then ## 3 Mins
                break;
                           fi


                           if [ $(($t_current-$t_perCurrent)) -ge 4 ]; then ##not continue
                                t_start=$(date +%s) ### set current time to Seconds
                total=1
                t_perCurrent=$t_start
               else
                        total=$(($total+1))
                    t_perCurrent=$(date +%s) ### set current time to Seconds
                           fi       
            fi          
    #   else
    #       echo  `date "+%Y-%m-%d %H:%M:%S"`"#"Cpu Usage Low  : $mainPID $myStatus  ${memInfo%%m}   ${cpuRatio%%%} $pName >> $LOGFILE
        fi
        if [ -z "$pName" ]; then

                break
        fi
        if [ "$myStatus" = "Z" ]; then
                break
        fi

done

if [  $total -ge $MaxTimes ]; then
    echo "`date "+%Y-%m-%d %H:%M:%S"`#Cpu usage run high duration 3 Mins!~"  >> $LOGFILE
    echo "`date "+%Y-%m-%d %H:%M:%S"`#System will reboot application~"       >> $LOGFILE
    killall SubProcess
    killall MainProcess
    #重启自启动的Shell
    /etc/init.d/mystart.sh monitor 

    t_start=0
    t_perCurrent=0
    t_current=0
    total=0

    mainPID=""
    myStatus=""
    memInfo=""
    cpuRatio=""
    pName=""
    eval $(top -n 1| grep "MainProcess" | grep -v grep | awk  {'printf("mainPID=%s;myStatus=%s;memInfo=%s;cpuRatio=%s;pName=%s\n",$1,$4,$5,$7,$8)'})
    echo `date "+%Y-%m-%d %H:%M:%S"`"#"$mainPID $myStatus  ${memInfo%%m}   ${cpuRatio%%%} $pName
    sleep 30
    continue
fi
if [ -z "$pName" ]; then
    echo "`date "+%Y-%m-%d %H:%M:%S"`#MainProcess is not exist!!"  >> $LOGFILE
    echo "`date "+%Y-%m-%d %H:%M:%S"`#System will reboot application~"       >> $LOGFILE
    killall SubProcess
    /etc/init.d/mystart.sh monitor
    mainPID=""
    myStatus=""
    memInfo=""
    cpuRatio=""
    pName=""
    eval $(top -n 1| grep "MainProcess" | grep -v grep | awk  {'printf("mainPID=%s;myStatus=%s;memInfo=%s;cpuRatio=%s;pName=%s\n",$1,$4,$5,$7,$8)'})
    echo `date "+%Y-%m-%d %H:%M:%S"`"#"$mainPID $myStatus  ${memInfo%%m}   ${cpuRatio%%%} $pName
    sleep 30
    continue
fi
if [ "$myStatus" = "Z" ]; then
    echo "`date "+%Y-%m-%d %H:%M:%S"`#MainProcess  is Z  status!!"  >> $LOGFILE
    echo "`date "+%Y-%m-%d %H:%M:%S"`#System will reboot application~"       >> $LOGFILE
    killall SubProcess
    killall MainProcess
    reboot
fi
done
echo "`date "+%Y-%m-%d %H:%M:%S"`"#"End ">> $LOGFILE

二、自启动的Shell代码

#!/bin/sh
/home/root/SubProcess &                                                       
/home/root/MainProcess -qws &  

if [ $1 != "Monitor" ]; then
sleep 30

/home/root/HealthMonitor.sh &
fi
没有更多推荐了,返回首页