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