QT之QLocalSocket下的两进程互相守护
在Qt应用程序开发中,进程间通信(IPC)是一个常见的需求。QLocalSocket是Qt提供的一个强大的本地套接字类,它通过基于套接字的接口,使多个进程能够无缝交换数据,非常适合需要本地通信的场景。专门用于同一台机器上不同进程之间的高效通信。与传统的TCP/UDP网络套接字不同,QLocalSocket使用本地套接字(在Unix系统上通常是Unix域套接字,在Windows上是命名管道),提供了更高的性能和更低的延迟。
一、QLocalSocket的特点
优势
- 高性能: 本地通信避免了网络协议栈的开销
- 安全性: 通信仅限于本机,不会暴露到网络
- 简单易用: API设计与QTcpSocket类似,学习成本低
- 跨平台: 在不同操作系统上提供一致的接口
适用场景
- 主进程与子进程之间的数据交换
- 多个独立应用程序之间的协作
- 客户端-服务器架构的本地应用
- 进程间状态同步和事件通知
基本概念
QLocalSocket通常与QLocalServer配对使用:
- QLocalServer: 作为服务器端,监听连接请求
- QLocalSocket: 作为客户端,连接到服务器
二、两进程互相守护示例
1、简述
因为这个守护逻辑可以抽象成一个独立类GuardianService,只需传入:
本进程名称(或 socket 名)
对方进程名称
对方启动路径(用于崩溃后重启)
2、源码示例
// GuardianService.h
#ifndef GUARDIANSERVICE_H
#define GUARDIANSERVICE_H#include <QObject>
#include <QLocalServer>
#include <QLocalSocket>
#include <QTimer>
#include <QProcess>
#include <QDebug>class GuardianService : public QObject {Q_OBJECT
public:static GuardianService* init(const QString &selfSocketName,const QString &peerSocketName,const QString &peerExecutablePath,QObject *parent = nullptr);private:explicit GuardianService(const QString &selfName,const QString &peerName,const QString &peerPath,QObject *parent = nullptr);void start();void setupServer();void connectToPeer();void tryRestartPeer();private slots:void onNewConnection();void onHeartbeatReceived();void onHeartbeatTimeout();void onPeerDisconnected();private:QString selfSocket;QString peerSocket;QString peerPath;QLocalServer server;QLocalSocket *peerClientSocket;QTimer heartbeatSendTimer;QTimer heartbeatTimeoutTimer;
};#endif // GUARDIANSERVICE_H// GuardianService.cpp
#include "GuardianService.h"GuardianService* GuardianService::init(const QString &selfSocketName,const QString &peerSocketName,const QString &peerExecutablePath,QObject *parent) {GuardianService *service = new GuardianService(selfSocketName, peerSocketName, peerExecutablePath, parent);service->start();return service;
}GuardianService::GuardianService(const QString &selfName,const QString &peerName,const QString &peerPath,QObject *parent): QObject(parent),selfSocket(selfName),peerSocket(peerName),peerPath(peerPath),peerClientSocket(new QLocalSocket(this)) {connect(&heartbeatSendTimer, &QTimer::timeout, this, [this]() {if (peerClientSocket->state() == QLocalSocket::ConnectedState) {peerClientSocket->write("ping");peerClientSocket->flush();}});connect(&heartbeatTimeoutTimer, &QTimer::timeout, this, &GuardianService::onHeartbeatTimeout);connect(peerClientSocket, &QLocalSocket::disconnected, this, &GuardianService::onPeerDisconnected);
}void GuardianService::start() {setupServer();connectToPeer();heartbeatSendTimer.start(2000); // 每2秒发送心跳heartbeatTimeoutTimer.start(5000); // 最多5秒无回应
}void GuardianService::setupServer() {QLocalServer::removeServer(selfSocket);if (!server.listen(selfSocket)) {qWarning() << "[Guardian] Failed to listen on socket:" << selfSocket << server.errorString();return;}connect(&server, &QLocalServer::newConnection, this, &GuardianService::onNewConnection);
}void GuardianService::connectToPeer() {if (peerClientSocket->state() != QLocalSocket::UnconnectedState)peerClientSocket->abort();peerClientSocket->connectToServer(peerSocket);
}void GuardianService::onNewConnection() {QLocalSocket *incoming = server.nextPendingConnection();connect(incoming, &QLocalSocket::readyRead, this, &GuardianService::onHeartbeatReceived);connect(incoming, &QLocalSocket::disconnected, incoming, &QLocalSocket::deleteLater);
}void GuardianService::onHeartbeatReceived() {heartbeatTimeoutTimer.start(5000); // 重置超时计时器QLocalSocket *sender = qobject_cast<QLocalSocket *>(sender());if (sender) sender->readAll();
}void GuardianService::onHeartbeatTimeout() {qWarning() << "[Guardian] Peer timeout, attempting restart...";tryRestartPeer();
}void GuardianService::onPeerDisconnected() {qWarning() << "[Guardian] Disconnected from peer. Reconnecting...";connectToPeer();
}void GuardianService::tryRestartPeer() {QProcess::startDetached(peerPath);heartbeatTimeoutTimer.start(5000); // 等待新实例心跳
}
3、使用方法
在进程 A 启动代码中调用:
GuardianService::init("procA", "procB", "procB.exe");
在进程 B 中使用:
GuardianService::init("procB", "procA", "procA.exe");
4、总结
利用
QLocalSocket
无需占用 TCP/UDP 端口;采用非侵入式心跳通信机制;
一方挂掉后 3 秒内自动拉起;
不依赖任务管理器或进程列表扫描;
轻量、跨平台。