QT January 16, 2020

【QT】进程间通信 -- 使用命名管道实现qt应用程序只运行一个实例

Words count 4.5k Reading time 4 mins. Read count 0

前言

在项目中,会遇到这么一个需求,应用程序只能存在一个运行实例。关于这需求,网上流行几种实现方式:

  1. 通过QSharedMemory实现
  2. 使用官方提供的QTSingleApplication
  3. 使用QLocalServer和QLocalSocket

本文章主要介绍第三种方式

实现思路

  1. 继承QApplicaiton或者QCoreApplication自定义一个SingleApplication
  2. 在SingleApplication构造函数中创建一个QLocalSocket连接指定server_name的server,这时有两种情况:
    2.1 假如没有连接成功,则代表没有运行实例,这时允许程序运行,并创建一个指定server_name的QLocalServer用来监听连接
    2.2 假如连接成功,从第二步可以发现,这时已经存在了一个运行实例,这时就不允许再创建新的运行实例

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
SingleApplication::SingleApplication(int &argc, char **argv)
: QApplication(argc, argv)
{
m_serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
initServer();
}

void SingleApplication::onNewConnection()
{
QLocalSocket *socket = m_server->nextPendingConnection();
if (socket)
{
socket->waitForReadyRead(1000);
delete socket;
}
}

void SingleApplication::initServer()
{
QLocalSocket socket;

// 连接以应用程序名称为server name的server
// 如果连接不上则代表未启动,此时创建一个新的server
m_isRunning = false;
socket.connectToServer(m_serverName);
if (socket.waitForConnected())
{
m_isRunning = true;
return;
}

m_server = new QLocalServer(this);
connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
if (!m_server->listen(m_serverName))
{
// 此时监听失败,可能是程序崩溃是残留进程的服务所导致,移除之
if (QAbstractSocket::AddressInUseError == m_server->serverError())
{
QLocalServer::removeServer(m_serverName);
m_server->listen(m_serverName);
}
}
}
0%