做電子商務(wù)系統(tǒng)網(wǎng)站建設(shè)在線搭建網(wǎng)站
Qt 進(jìn)程守護(hù)程序
簡單粗暴的監(jiān)控,方法可整合到其他代碼。
一、windows環(huán)境下
1、進(jìn)程查詢函數(shù)
processCount函數(shù)用于查詢系統(tǒng)所有運(yùn)行的進(jìn)程中該進(jìn)程運(yùn)行的數(shù)量,比如啟動了5個A進(jìn)程,該函數(shù)查詢返回的結(jié)果就為5。
windows下使用了API接口查詢進(jìn)程信息,該函數(shù)純C++無Qt庫相關(guān)代碼,注釋對代碼進(jìn)行了詳細(xì)解釋。
int processCount(const char* processName)
{int countProcess = 0;//CreateToolhelp32Snapshot 獲取系統(tǒng)中正在運(yùn)行的進(jìn)程信息,線程信息等HANDLE toolHelp32Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (((int)toolHelp32Snapshot) != -1){PROCESSENTRY32 processEntry32;processEntry32.dwSize = sizeof(processEntry32);if(Process32First(toolHelp32Snapshot, &processEntry32)) //判斷進(jìn)程獲取首進(jìn)程是否存在{do{int iLen = 2 * wcslen(processEntry32.szExeFile); //wcslen - 計算寬字符串的長度char* currentProcessName = new char[iLen + 1];wcstombs(currentProcessName, processEntry32.szExeFile, iLen + 1); //將寬字符轉(zhuǎn)換成多字符if (strcmp(processName, currentProcessName) == 0) //對比進(jìn)程名countProcess++;delete []currentProcessName;}while (Process32Next(toolHelp32Snapshot, &processEntry32)); //進(jìn)程獲取函數(shù),獲取下一個進(jìn)程名}//關(guān)閉一個內(nèi)核對象。其中包括文件、文件映射、進(jìn)程、線程、安全和同步對象等。CloseHandle(toolHelp32Snapshot);}return countProcess;
}
2、進(jìn)程守護(hù)代碼
進(jìn)程守護(hù)其實(shí)就是使用一個進(jìn)程去定時查詢另外一個被守護(hù)的進(jìn)程是否存在,不存在則需要啟動該進(jìn)程。代碼如下,運(yùn)行時,首先需要獲取被守護(hù)的進(jìn)程APP,使用讀取配置文件的方式,如果配置文件不存在(首次啟動該代碼),則需要選擇被守護(hù)的進(jìn)程,然后將選擇的APP路勁存入配置文件,供下次啟動讀取使用。
#include <QApplication>
#include <QFileDialog>
#include <QSettings>
#include <windows.h>
#include <QDebug>
#include <QDateTime>int main(int argc, char *argv[])
{QSettings sets("sys.ini", QSettings::IniFormat);QString targetExePath = sets.value(KEY_EXE_PATH).toString();if ("" == targetExePath){//首次需要選擇 被守護(hù)的進(jìn)程QString exepath = QFileDialog::getOpenFileName(nullptr, "選擇程序", "D:/", "Exe files (*.exe)");if ("" != exepath)sets.setValue(KEY_EXE_PATH, exepath); //寫入配置文件}while (1) //死循環(huán),不斷查詢判斷{//targetExePath = sets.value(KEY_EXE_PATH).toString();QString exeName = targetExePath.split('/').last();QDateTime strtTime = QDateTime::currentDateTime();int countProcess = processCount(exeName.toStdString().c_str()); // 查詢該進(jìn)程運(yùn)行數(shù)量qDebug()<<"use times for Query process:"<<strtTime.msecsTo(QDateTime::currentDateTime())<<"(ms) countProcess:"<<countProcess;if (countProcess == 0)system(targetExePath.toStdString().c_str()); //關(guān)閉狀態(tài) 重啟進(jìn)程,注意:這里實(shí)際運(yùn)行會阻塞在這里,一直等到被守護(hù)的線程結(jié)束。Sleep(3000);}
}
二、linux環(huán)境下
1、進(jìn)程查詢函數(shù)
原理: 使用 popen函數(shù) + pidof命令 查詢對應(yīng)進(jìn)程的pid,該方法的缺點(diǎn)就是不能像windows那樣讀取所有進(jìn)程名從而獲取該進(jìn)程運(yùn)行的數(shù)量。所以,如果一個程序加載多個進(jìn)程(同程序進(jìn)程名相同,pid不同),使用該方法只能獲取最后一個啟動的進(jìn)程pid。
popen屬于標(biāo)準(zhǔn)I/O函數(shù)庫中函數(shù),使用該函數(shù)啟動另外一個進(jìn)程去執(zhí)行一個shell命令行。
這里我們稱調(diào)用popen的進(jìn)程為父進(jìn)程,由popen啟動的進(jìn)程稱為子進(jìn)程。
popen函數(shù)還創(chuàng)建一個管道用于父子進(jìn)程間通信。父進(jìn)程要么從管道讀信息,要么向管道寫信息,至于是讀還是寫取決于父進(jìn)程調(diào)用popen時傳遞的參數(shù)。
實(shí)現(xiàn)函數(shù)如下,函數(shù)參數(shù)輸入進(jìn)程名,返回進(jìn)程的pid,如果返回0,則表示進(jìn)程不存在或未運(yùn)行。
void Widget::watchdog()
{//守護(hù)進(jìn)程QTimer* updateTimer = new QTimer(this);connect(updateTimer, SIGNAL(timeout()), this, SLOT(checkApp()));updateTimer->start(300);
}
void Widget::checkApp()
{if (getProcessPidByName("AppName") == 0) {system("cd /sdcard");system("./AppName &");qDebug() << "";qDebug() << " _ __ _____ _ ";qDebug() << " | |/ / / ____|| | ";qDebug() << " | ' / __ _ _ __ __ _ | | | |__ _ _ __ _ _ __ __ _ ";qDebug() << " | < / _` || '_ \\ / _` | | | | '_ \\ | | | | / _` || '_ \\ / _` |";qDebug() << " | . \\ | (_| || | | || (_| | | |____ | | | || |_| || (_| || | | || (_| |";qDebug() << " |_|\\_\\ \\__,_||_| |_| \\__, | \\_____||_| |_| \\__,_| \\__,_||_| |_| \\__, |";qDebug() << " __/ | __/ |";qDebug() << " |____/ |____/ ";qDebug() << "";}
}
int Widget::getProcessPidByName(const char* proc_name)
{FILE* fp;char buf[100];char cmd[200] = { '\0' };int pid = -1;sprintf(cmd, "pidof %s", proc_name);if ((fp = popen(cmd, "r")) != NULL) {if (fgets(buf, 255, fp) != NULL)pid = atoi(buf);}pclose(fp);return pid;
}