Qt实现应用程序单实例运行--LocalServer方式

使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现。该方法实现简单,代码简洁。

但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸崩溃,会导致共享内存无法释放,从而无法重新运行程序!

 

所以应该寻找其他的使Qt应用程序能够单实例运行的方案。于是找到LocalSocket和LocalServer通讯方案(据说Qt官方商业版的QSingleApplication的原理好像跟这个差不多)。

“要用到Qt的QLocalSocket,QLocalServer类,这两个类从接口上看和网络通信socket没有区别,但是它并不是真正的网络API,只是模仿了而已。这两个类在Unix/Linux系统上采用Unix域socket实现,而在Windows上则采用有名管道(named pipe)来实现。”

参见:

http://www.oschina.net/code/snippet_54100_629

http://blog.csdn.net/qq19831030qq/article/details/6199896

 

上面的方案实际操作过程中出现很多问题:

QString serverName = QCoreApplication::applicationName(); //获取到的serverName为空

为了解决上面的问题,最直接的测试方法是先手动指定一个serverName,

然后将QFile::remove(m_localServer->serverName());改成QFile::remove(serverName);

 

当手动指定serverName时,习惯上将serverName设为当前的应用程序名,在linux下这又导致下面的问题

QFile::remove(m_localServer->serverName()); //执行删除失败(实际测试发现失败原因是:尝试删除应用程序文件自身!)

 

 上面的两个问题导致Qt应用程序无法单实例运行。

 

#include "singleapplication.h"
#include <QDataStream>

#define TIME_OUT 500

SingleApplication::SingleApplication(int &argc, char **argv) :
    QApplication(argc, argv)
  ,w(NULL)
  ,_isRunning(false)
  ,_localServer(NULL)
{
    _serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
    _initLocalConnection();
}


 bool SingleApplication::isRunning()
 {
   return _isRunning;

 }

void SingleApplication::_initLocalConnection()
{
    _isRunning = false;
    QLocalSocket socket;
    socket.connectToServer(_serverName);
    if (socket.waitForConnected(TIME_OUT)) {
        _isRunning = true;
        return;
    }
    _newLocalServer();
}


void SingleApplication::_newLocalServer()
{
    _localServer = new QLocalServer(this);
    connect(_localServer, SIGNAL(newConnection()), this, SLOT(_newLocalConnection()));

    if (_localServer->listen(_serverName)) {
        if (_localServer->serverError() == QAbstractSocket::AddressInUseError) {
            QLocalServer::removeServer(_serverName);
            _localServer->listen(_serverName);
        }
    }
}

void SingleApplication::_activateWindow()
{
    if (w) {
        //w->setWindowState(w->windowState() & ~Qt::WindowMinimized);
        w->show();
        w->raise();
        w->activateWindow();
    }
}

void SingleApplication::_newLocalConnection()
{
    QLocalSocket *socket = _localServer->nextPendingConnection();
    if (socket) {
        socket->waitForReadyRead(2 * TIME_OUT);
        delete socket;

        _activateWindow();
    }
}


头文件代码如下:

#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H

#include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
#include <QtWidgets>

class SingleApplication : public QApplication
{
    Q_OBJECT
public:
    explicit SingleApplication(int &argc, char **argv);
    bool isRunning();
    QWidget *w;

signals:


public slots:
    void _newLocalConnection();

private:
    void _initLocalConnection();
    void _newLocalServer();
    void _activateWindow();


    QLocalServer *_localServer;
    QString _serverName;
    bool _isRunning;
    
};

#endif // SINGLEAPPLICATION_H


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值