概述
一些重要的程序,必须让它一直跑着;而且还要时时关心它的状态——不能让它出现死锁现象。当然,如果一个主程序会出现死锁,肯定是设计或者编程上的失误。我们首要做的事是,把这个Bug揪出来。但如果时间紧迫,这个Bug又“飘忽不定”,那么,我们还是先写一个软件“看门狗”,暂时应一下急吧。
“看门狗”的需求描述:“看门狗”的运行不出现界面窗口,具有一定的隐蔽性;定时判断目标进程是否运行在当前系统中,如果没有则启动目标进程;判断目标进程是否“没有响应”,如果是则终止目标进程;如果目标进程“没有响应”的次数超过一定的数量,则将计算机系统重启。
公共看门狗程序:
1、公共的制定一条规则,使用者根据规则写入配置文件,程序根据配置文件进行读取分析
2、可以部署在任意一台程序上,每毫秒检测程序进程是否存在,不存在的时候拉起程序。
一、区分__linux__ 还是 __WIN32
void excuteorder::Getps()
{
//#ifdef __linux_
CIniFile iniFile = CIniFile(QCoreApplication::applicationDirPath()+ CNEEDLEWATCHDOG);
QString strSLBPort = iniFile.GetValue("demon", "SLBHPort");
qDebug()<<"strSLBPort"<<strSLBPort;
char cmd[128] = {0};
sprintf(cmd, "ps -aux | grep 'aaa' | grep -v grep | wc -l");
QString str = ExcuteCmd(cmd);
qDebug()<<"str:"<<str;
if ( str.toInt() <= 1 )
{
qDebug()<<"start";
char ExcuteProcedureCMD[128] = {0};
sprintf(ExcuteProcedureCMD, "cd /home/lky/Documents/aaa/binl && ./aaa &"); //执行程序命令
QString result = ExcuteCmd(ExcuteProcedureCMD);
qDebug()<<"result:"<<result;
} else
{
qDebug()<<"no need";
/***endl***/
}
//#elif _WIN32
//qDebug()<<"Configuring on/for Windows";
//#endif
}
二、监控要做到毫秒级别,Qt使用QTimer类来实现。(QTimer最小时间单位是毫秒)
QTimer* mTimer = new QTimer(this);
connect(mTimer,SIGNAL(timeout()),this,SLOT(Getps()));
mTimer->start(1000);
每毫秒会回调Getps()这个函数。
三、然后就是程序运行Linux命令的接口,会返回命令的result
QString excuteorder::ExcuteCmd(QString Cmd)
{
QString str;
char line[512] = {0};
FILE *pFile = popen(Cmd.toStdString().c_str(), "r");
if(pFile == NULL)
{
return "";
}
while(fgets(line, sizeof(line), pFile)){
RemoveSpecialChar("\n", line);
str = line;
break;
}
pclose(pFile);
if(strlen(line) <= 0)
{
return "";
}
return str;
}
int excuteorder::RemoveSpecialChar(const char *SpeChar, char *src)
{
int i,j,m,k;
int intSpeCharLen = strlen(SpeChar);
int intSrcLen = strlen(src);
for(i = 0; i < intSpeCharLen; i++){//有几个特特殊字符
int intSpeCharNum = 0;
for(j = 0;j < intSrcLen; j++){//遍历源串中某一特殊字符的个数
if(SpeChar[i]== src[j]){
intSpeCharNum ++;
}
}
for(j = 0;j < intSpeCharNum; j++){//遍历去除所有某一个字符
for(m = 0; m < intSrcLen ; m++){//从源串中查找特殊字符
if(SpeChar[i]== src[m]){
for(k = m; k < intSrcLen; k++){//查找到某一个特殊字符后面的字符一次向前移动
src[k] = src[k+1];
}
intSrcLen--;
break;
}
}
}
}
return 0;
}
调用ExcuteCmd接口拼接要执行的命令就能返回结果了。
然后还有一块要读取配置文件的。因为要做成公共,所以程序放到任意一台其他的服务器上,只要根据规定的规则写道ini,程序就会识别。只需要导入已经成熟的Qt读写配置文件
#ifndef CINIFILE_H
#define CINIFILE_H
#include "CComm.h"
#include <QSettings>
class CIniFile
{
public:
CIniFile(QString Path);
virtual ~CIniFile();
//向ini文件指定块中写key和value
int SetValue(QString Block, QString Key, QString Value);
//获取ini文件指定块中key和value
QString GetValue(QString Block, QString Key, QString def = "");
//设置编码格式,输入参数是 QTextCodec 支持的编码格式名称
void setIniCodec(const char * CodecName);
private:
QSettings *m_IniFile;
};
#endif // CINIFILE_H
#include "CIniFile.h"
CIniFile::CIniFile(QString Path)
{
m_IniFile = new QSettings(Path, QSettings::IniFormat);
}
CIniFile::~CIniFile()
{
if(m_IniFile != NULL){
delete m_IniFile;
}
}
/**
* @brief CIniFile::SetValue
* 向ini文件指定块中写key和value
* @param Block 块名称
* @param Key key名称
* @param Value value值
* @return 0 success
*/
int CIniFile::SetValue(QString Block, QString Key, QString Value)
{
QString strLink = "/";
m_IniFile->setValue(Block + strLink+Key, Value);
return SUCCESS;
}
/**
* @brief CIniFile::GetValue
* 获取ini文件指定块中key和value
* @param Block 块名称
* @param Key key名称
* @return 返回value值
*/
QString CIniFile::GetValue(QString Block, QString Key, QString def)
{
QString strLink = "/";
QString strRes = m_IniFile->value(Block + strLink + Key).toString();
if(strRes.length() <= 0){
strRes = def;
}
return strRes;
}
void CIniFile::setIniCodec(const char *CodecName)
{
m_IniFile->setIniCodec(CodecName);
}
举例这个就是读取配置文件内容的规则
CIniFile iniFile = CIniFile(QCoreApplication::applicationDirPath()+ CNEEDLEWATCHDOG);
QString strSLBPort = iniFile.GetValue("demon", "SLBHPort");
配置内容
/---------------------------------以下是程序写入Linux命令的接口【命令带拼接的参数】---------------------------------/
/**
* @brief CDevicesManagerDView::ExcuteCmdList
* 执行shell指令 返回多行
* @param Cmd shell指令
* @param strList 返回信息列表
* @return 0 success -1202 到 -1301 err
*/
int CNeedleDemon::ExcuteCmdList(QString Cmd, QStringList& strList)
{
log_debug("@@@ ExcuteCmdList start Cmd:%s", Cmd.toStdString().c_str());
char line[512] = {0};
FILE *pFile = popen(Cmd.toStdString().c_str(), "r");
if(pFile == NULL){
log_error("fopen Cmd:%s failed!", Cmd.toStdString().c_str());
return CNSTREAMSER_EXCUTECMDLIST_EXCUTEFAILED;
}
while(fgets(line, sizeof(line), pFile)){
RemoveSpecialChar("\n", line);
strList.append(line);
}
if(strList.count() <= 0){
return CNSTREAMSER_EXCUTECMDLIST_RESULTNULL;
}
log_debug("@@@ ExcuteCmdList end");
return SUCCESS;
}
//字符串中去除特殊字符函数
int CNeedleDemon::RemoveSpecialChar(const char *SpeChar, char* src)
{
int i,j,m,k;
int intSpeCharLen = strlen(SpeChar);
int intSrcLen = strlen(src);
for(i = 0; i < intSpeCharLen; i++){//有几个特特殊字符
int intSpeCharNum = 0;
for(j = 0;j < intSrcLen; j++){//遍历源串中某一特殊字符的个数
if(SpeChar[i]== src[j]){
intSpeCharNum ++;
}
}
for(j = 0;j < intSpeCharNum; j++){//遍历去除所有某一个字符
for(m = 0; m < intSrcLen ; m++){//从源串中查找特殊字符
if(SpeChar[i]== src[m]){
for(k = m; k < intSrcLen; k++){//查找到某一个特殊字符后面的字符一次向前移动
src[k] = src[k+1];
}
intSrcLen--;
break;
}
}
}
}
return 0;
}
/---------------------------------以下是程序写入Linux命令的接口---------------------------------/
int CNeedleDemon::Excute(QString Cmd)
{
printf("cmd:%s\n", Cmd.toStdString().c_str());
FILE *pFile = popen(Cmd.toStdString().c_str(), "r");
if(pFile == NULL){
qDebug()<<"fopen "<< Cmd << " failed!";
return -1;
}
pclose(pFile);
return SUCCESS;
}