## 一、前言说明
最近有个定制需求,希望程序能够一直运行,比如在windows上运行的程序,很可能无法保证不出故障崩溃,有时候可能是程序内部处理异常导致的崩溃,比如有些
数据解析
没有考虑到一些极端的情况,还有就是用户主动关闭了程序,可能是误关闭,而有些程序,又必须7*24小时运行,所以必须要有个守护进程,能够实时监测程序的运行情况,一旦发现程序死机或者不存在了,则重启程序。
在一些
嵌入式板子上,有个看门狗的功能,打开看门狗驱动后,定时喂狗,如果程序死了或者不存在了,则喂狗超时,会触发硬件重启,这个比较彻底。如果用纯软件实现呢,一般不会去重启系统,尽管
执行对应的重启指令也可以做到,一般会重启程序,第一步是先kill掉程序,因为可能程序还在只是死机了,第二步是重新启动程序,在某些环境中,有些程序可能还有托盘图标残留,所以可能还需要结束桌面进程,然后再启动桌面进程,这样残留的托盘图标也会清除,因为很多时候意外关闭程序,对应托盘图标不会退出的。
使用软件来实现程序启动器,一般都会采用udp通信的方式,软件端监听对应端口,收到hello指令后,回复自己的程序名称加上ok数据,守护端这边不断的发hello指令,收到对应ok后就表示正常,将
错误计数清零,每一轮没有收到ok则错误计数累加,连续超过多少次比如3次则认为程序死了,然后就去执行重启程序,为什么用udp,因为无连接,资源占用极低,而且基本上都是本机内部通信,也就是127.0.0.1这个地址进行交互,所以几乎不会给现有的程序造成负担。
## 二、效果图
window.open('http://www.qtcn.org/bbs/attachment/Mon_2509/44_110085_5ca9da580e22da5.jpg?91');" style="max-width:700px;max-height:700px;" onload="if(is_ie6&&this.offsetWidth>700)this.width=700;" > ## 三、代码使用
```cpp
#include "frmlivetool.h"
#include "ui_frmlivetool.h"
#include "qthelper.h"
#include "liveserver.h"
#include "trayicon.h"
frmLiveTool::frmLiveTool(QWidget *parent) : QWidget(parent), ui(new Ui::frmLiveTool)
{
ui->setupUi(this);
this->initForm();
QtHelper::setFormInCenter(this);
on_btnStart_clicked();
}
frmLiveTool::~frmLiveTool()
{
delete ui;
}
void frmLiveTool::closeEvent(QCloseEvent *e)
{
if (QtHelper::showMessageBoxQuestion("确定要退出吗? 退出后所有服务将停止!") != QMessageBox::Yes) {
e->ignore();
return;
}
if (AppConfig::UseTray) {
TrayIcon::Instance()->setVisible(false);
}
}
void frmLiveTool::showEvent(QShowEvent *)
{
AppConfig::HideTray = false;
AppConfig::writeConfig();
}
void frmLiveTool::changeEvent(QEvent *)
{
//启用托盘服务则隐藏主
界面 if (this->windowState() == Qt::WindowMinimized) {
if (AppConfig::UseTray) {
this->hide();
AppConfig::HideTray = true;
AppConfig::writeConfig();
TrayIcon::Instance()->showMessage("提示", "程序最小化到后台运行!");
}
}
}
void frmLiveTool::initForm()
{
//设置托盘图标和主窗体
if (AppConfig::UseTray) {
TrayIcon::Instance()->setIcon(":/main.ico");
TrayIcon::Instance()->setMainWidget(this);
TrayIcon::Instance()->setVisible(true);
}
//设置开机启动
QtHelper::runWithSystem(AppConfig::AutoRun);
ui->txtAppName->setText(AppConfig::AppName);
ui->labCount->setText(
QString("已重启 %1 次").arg(AppConfig::ReStartCount));
ui->labInfo->setText(QString("最后一次重启在 %1").arg(AppConfig::ReStartTime));
connect(LiveServer::Instance(), SIGNAL(reStart()), this, SLOT(reStart()));
LiveServer::Instance()->setPara(AppConfig::AppPath, AppConfig::AppName, AppConfig::AppPort, AppConfig::MaxCount, AppConfig::UpdateDesk);
}
void frmLiveTool::reStart()
{
AppConfig::ReStartCount++;
AppConfig::ReStartTime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
AppConfig::writeConfig();
ui->labCount->setText(QString("已重启 %1 次").arg(AppConfig::ReStartCount));
ui->labInfo->setText(QString("最后一次重启在 %1").arg(AppConfig::ReStartTime));
}
void frmLiveTool::on_btnOk_clicked()
{
AppConfig::AppName = ui->txtAppName->text();
if (AppConfig::AppName.isEmpty()) {
QMessageBox::critical(this, "提示", "应用程序名称不能为空!");
ui->txtAppName->setFocus();
return;
}
AppConfig::writeConfig();
ui->btnStart->setEnabled(true);
LiveServer::Instance()->setPara(AppConfig::AppPath, AppConfig::AppName, AppConfig::AppPort, AppConfig::MaxCount, AppConfig::UpdateDesk);
}
void frmLiveTool::on_btnStart_clicked()
{
if (ui->btnStart->text() == "开始") {
LiveServer::Instance()->start(AppConfig::Interval);
ui->btnStart->setText("暂停");
} else {
LiveServer::Instance()->stop();
ui->btnStart->setText("开始");
}
}
void frmLiveTool::on_btnReset_clicked()
{
AppConfig::ReStartCount = -1;
this->reStart();
QMessageBox::information(this, "提示", "重置配置
文件成功!");
}
```
## 四、相关地址
1. 国内站点:[
https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
2. 国际站点:[
https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
3. 个人作品:[
https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
4. 文件地址:[
https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A](https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A) 提取码:o05q 文件名:bin_map.zip