天天看点

Qt 进程守护程序(windows、linux)

一、windows环境下

1、进程查询函数

processCount函数用于查询系统所有运行的进程中该进程运行的数量,比如启动了5个A进程,该函数查询返回的结果就为5。

windows下使用了API接口查询进程信息,该函数纯C++无Qt库相关代码,注释对代码进行了详细解释。

int processCount(const char*  processName)
{
    int countProcess = 0;
    //CreateToolhelp32Snapshot 获取系统中正在运行的进程信息,线程信息等
    HANDLE toolHelp32Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (((int)toolHelp32Snapshot) != -1)
    {
        PROCESSENTRY32 processEntry32;
        processEntry32.dwSize = sizeof(processEntry32);
        if(Process32First(toolHelp32Snapshot, &processEntry32))      //判断进程获取首进程是否存在
        {
            do
            {
                int iLen = 2 * wcslen(processEntry32.szExeFile);    //wcslen - 计算宽字符串的长度
                char* currentProcessName = new char[iLen + 1];
                wcstombs(currentProcessName, processEntry32.szExeFile, iLen + 1);    //将宽字符转换成多字符
                if (strcmp(processName, currentProcessName) == 0)      //对比进程名
                    countProcess++;
                delete []currentProcessName;
            }while (Process32Next(toolHelp32Snapshot, &processEntry32));     //进程获取函数,获取下一个进程名
        }
        //关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。
        CloseHandle(toolHelp32Snapshot);
    }
    return countProcess;
}      

2、进程守护代码

进程守护其实就是使用一个进程去定时查询另外一个被守护的进程是否存在,不存在则需要启动该进程。代码如下,运行时,首先需要获取被守护的进程APP,使用读取配置文件的方式,如果配置文件不存在(首次启动该代码),则需要选择被守护的进程,然后将选择的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)
    {
        //首次需要选择 被守护的进程
        QString exepath = QFileDialog::getOpenFileName(nullptr, "选择程序", "D:/", "Exe files (*.exe)");
        if ("" != exepath)
            sets.setValue(KEY_EXE_PATH, exepath);       //写入配置文件
    }
    while (1)        //死循环,不断查询判断
    {
        //targetExePath = sets.value(KEY_EXE_PATH).toString();
        QString exeName = targetExePath.split('/').last();

        QDateTime strtTime = QDateTime::currentDateTime();
        int countProcess = processCount(exeName.toStdString().c_str());   // 查询该进程运行数量
        qDebug()<<"use times for Query process:"<<strtTime.msecsTo(QDateTime::currentDateTime())<<"(ms)   countProcess:"<<countProcess;
        if (countProcess == 0)
            system(targetExePath.toStdString().c_str());        //关闭状态 重启进程,注意:这里实际运行会阻塞在这里,一直等到被守护的线程结束。
       Sleep(3000);
    }
}      

二、linux环境下

1、进程查询函数

原理: 使用 popen函数 + pidof命令 查询对应进程的pid,该方法的缺点就是不能像windows那样读取所有进程名从而获取该进程运行的数量。所以,如果一个程序加载多个进程(同程序进程名相同,pid不同),使用该方法只能获取最后一个启动的进程pid。

pid_t getProcessPidByName(const char *proc_name)
{
     FILE *fp;
     char buf[100];
     char cmd[200] = {'\0'};
     pid_t 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;
}      
int main(int argc, char *argv[])
{
    while(1)
    {
        if(getProcessPidByName("qtcreator") == -1)
        {
            printf("open APP qtcreator...");
            system("qtcreator &");        //启动软件
        }
        sleep(5);        //需要大于软件启动时间
    }
    return 0;
}