linux下对进程出错退出的重启

原创 2017年08月09日 14:51:16

简述: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






linux 后台进程如何不受shell退出的影响

ssh 关闭后仍保持当前运行的进程 由于各种原因,需要通过ssh登录linux或者unix主机,很多时候我们需要通过ssh的终端启动一 些服务或者运行一些程序,但是默认情况下,当我们关闭ssh终...
  • stonesharp
  • stonesharp
  • 2014年06月06日 17:34
  • 2509

linux 通过命令行在后台启动程序。当命令行窗体关闭时,程序不会被关闭

linux 通过命令行在后台启动程序。当命令行窗体关闭时,程序不会被关闭
  • wyj21js
  • wyj21js
  • 2016年01月08日 14:08
  • 2410

TCP socket异常关闭总结

游戏测试过程中发现某些socket错误经常出现,以下是测试游戏服务器时通常考虑的case. 服务器端: 1. Case:客户端程序正常运行的情况下,拔掉网线,杀掉客户端程序 目的:模拟客户端死机、系统...
  • u012841800
  • u012841800
  • 2014年03月06日 22:11
  • 4325

Linux下tomcat进程运行监视并自动重启的脚本

1,描述 我们需要写一个进程监控的脚本,目的是检测tomcat进程是否停掉,如果挂了,自动拉起,所以我们写了如下的脚本,参考了一些资料,希望对有需要的人有所帮助。 #!/bin/bash ec...
  • altand
  • altand
  • 2012年06月29日 10:03
  • 1797

linux下监视进程,若进程关闭则自动重启

从事嵌入式行业已经3年,说来惭愧,我目前除了电路系统设计,PCB设计,while(1)系统程序设计就基本上不会什么了。面对外面世界的巨大压力,我觉得提升自我已经是一件刻不容缓的事情,于是在上周开始,我...
  • funcye
  • funcye
  • 2013年04月28日 02:17
  • 583

Linux 下实现进程退出后自动重启

 Linux 下实现进程退出后自动重启 一般方案有2 1.采用脚本,网上很多,但对一些嵌入式系统因资源限制,大部分命令裁剪了,故不可行 2.采用fork,父进程等待子进程退出 一下采用f...
  • doitsjz
  • doitsjz
  • 2016年03月03日 18:32
  • 912

linux下定时重启jboss

  • 2017年09月27日 17:05
  • 14KB
  • 下载

linux下重启oracle

  • 2016年06月08日 11:51
  • 34KB
  • 下载

Tomcat在Linux下的定时重启

  • 2014年02月27日 11:09
  • 654KB
  • 下载

聊聊进程异常重启的问题------顺便详解linux句柄泄漏问题的定位(知识点: lsof -p xxx; ll /proc/xxx/fd)

之前做过嵌入式开发, linux环境玩代码, 这玩意儿最终是卖给用户。 产品一旦到用户手上, 要修复bug的代价就很大了, 而且, 由于是用户(个体)触发, 所以很多问题是不太好暴露出来的。 比如某些...
  • stpeace
  • stpeace
  • 2016年07月02日 09:53
  • 2856
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux下对进程出错退出的重启
举报原因:
原因补充:

(最多只允许输入30个字)