QProcess的应用:杀死固定进程并重启进程

来源:互联网 发布:mac上电话轰炸 编辑:程序博客网 时间:2024/06/02 09:16

问题:这两天遇到项目程序莫名其妙的运行异常,那么可能需要自动终结该进程并重启。
思路:为了判断主程序是否正常运行,我们可以这样做,写一个辅助程序跟主程序通讯,这里采用本地udp socket的方式保持联系。主程序向辅助程序定时发送确认包。当辅助程序检测到主程序在一定时间内(假设是3s)没有发送数据包,那么辅助程序则判定主程序异常,先尝试性杀死进程,并自动重启。在这里考虑到这个程序是一个辅助程序,那么就打算把他做成一个后台服务程序。
先看下辅助程序:
//main.cpp

#include "Widget.h"#include <QApplication>#include <QProcess>int main(int argc, char *argv[]){    QApplication a(argc, argv);    QProcess::startDetached("./xxx.exe");    Widget w;    return a.exec();}

//widget.h

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QUdpSocket>#include <QTimer>#include <QProcess>#include <QWidget>#include <QCloseEvent>namespace Ui {class Widget;}class Widget : public QWidget{    Q_OBJECTpublic:    explicit Widget(QWidget *parent = 0);    ~Widget();private slots:    void slotReadyRead();    void slotTimeout();private:    void initClass();    void killProcess();    void closeEvent(QCloseEvent*);private:    QUdpSocket *udpSocket;    QTimer *timer;    QProcess process;    QWidget *widget;private:    Ui::Widget *ui;};#endif // WIDGET_H

//widget.cpp

#include "Widget.h"#include "ui_Widget.h"Widget::Widget(QWidget *parent) :    QWidget(parent),    ui(new Ui::Widget){    ui->setupUi(this);    ui->plainTextEdit->appendPlainText("主程序运行中");    this->setWindowFlags(windowFlags() &~ (Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint));    this->hide();    initClass();}Widget::~Widget(){    udpSocket->close();    udpSocket->deleteLater();    udpSocket = nullptr;    timer->stop();    timer->deleteLater();    timer = nullptr;    delete ui;}void Widget::slotReadyRead(){    while(udpSocket->hasPendingDatagrams()){        QByteArray datagram;        datagram.resize(udpSocket->pendingDatagramSize());        QHostAddress senderHostAddress;        quint16 senderPort;        udpSocket->readDatagram(datagram.data(),datagram.size(),&senderHostAddress,&senderPort);        qDebug()<<"UdpSocket Recevie:"<<senderHostAddress<<senderPort<<datagram;    }    timer->start(3000);}//定时如果到了,杀死进程并重启void Widget::slotKillProcess(){    this->show();    ui->plainTextEdit->appendPlainText("程序异常!!!");    ui->plainTextEdit->appendPlainText("正在解决异常......");    timer->stop();    killProcess();    ui->plainTextEdit->appendPlainText("正在重新启动......");    QProcess::startDetached("./xxx.exe");    this->hide();}void Widget::initClass(){    udpSocket = new QUdpSocket(this);    if(udpSocket->bind(QHostAddress::LocalHost,20001,QAbstractSocket::ShareAddress)){        qDebug()<<"绑定20001端口成功";    }else{        qDebug()<<"绑定20001端口失败";    }    connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::slotReadyRead);    timer = new QTimer(this);    connect(timer,&QTimer::timeout,this,&Widget::slotKillProcess);}void Widget::killProcess(){    ui->plainTextEdit->appendPlainText("正在杀死进程xxx.exe");    QStringList args;    args<<"/F"<<"/IM"<<"xxx.exe"<<"/T";    process.start(QString("TASKKILL"),args);    process.waitForStarted();    process.waitForFinished(2000);    ui->plainTextEdit->appendPlainText("已经杀死进程xxx.exe");}void Widget::closeEvent(QCloseEvent *e){    e->ignore();}

如程序所见,我这里是先启动辅助程序,并会自动启动主程序,并等待主程序发送数据包,当第一个数据包发送过来,则启动定时器,如果三秒之内主程序没有再发送数据包到此端口,那么则调用slotKillProcess()方法,先杀死进程并再重启程序。为了让程序在后台运行,这里调用窗体类的hide();当异常时,再显示窗口,待主程序启动完成后再次回到后台。为了显示进程消息,这里在UI文件放了个plainTextEdit。
`
下面是主程序与辅助程序相应的通讯类
//AckNormal.h

#ifndef ACKNORMAL_H#define ACKNORMAL_H#include <QObject>#include <QUdpSocket>#include <QMessageBox>#include <QTimer>class AckNormal : public QWidget{    Q_OBJECTpublic:    explicit AckNormal(QWidget *parent = 0);    ~AckNormal();signals:private slots:    void slotTimeout();private:    void initClass();private:    QUdpSocket *udpSocket;    QTimer *timer;};#endif // ACKNORMAL_H

//AckNormal.cpp

#include "AckNormal.h"AckNormal::AckNormal(QWidget *parent) : QWidget(parent)  ,udpSocket(nullptr),timer(nullptr){    initClass();}AckNormal::~AckNormal(){    udpSocket->close();    udpSocket->deleteLater();    udpSocket = nullptr;    timer->stop();    timer->deleteLater();    timer = nullptr;}void AckNormal::slotTimeout(){    QByteArray ba("online");    udpSocket->writeDatagram(ba,QHostAddress::LocalHost,20001);}void AckNormal::initClass(){    udpSocket = new QUdpSocket(this);    if(!udpSocket->bind(QHostAddress::LocalHost,20000,QAbstractSocket::ShareAddress)){        QMessageBox::information(this,"Warning","绑定20000端口失败");        return;    }    timer = new QTimer(this);    connect(timer,&QTimer::timeout,this,&AckNormal::slotTimeout);    timer->start(1000);}

如上面程序所见,主程序启动后实例化AckNormal,会自动向辅助程序发送确认数据包。
至此一个简单的辅助程序就这样完成了。欢迎与各位Qt爱好者学习交流。

0 0
原创粉丝点击