Qt运行一个实例进程-3种方式简介

一:使用QLocalSocket

   方式:首先一个新的实例启动时,将尝试连接到同一个本地服务器,如果连接失败,则表示第一个实例进程,创建一个本地服务器。否则,进行退出。(.pro里加上QT += network)
voidMainWidget::initLocalConnection()
{
   is_running = false;
   QCoreApplication::setApplicationName("localserver");
    QStringserverName = QCoreApplication::applicationName();
   QLocalSocket socket;
   socket.connectToServer(serverName);
   if(socket.waitForConnected(500))
   {
       is_running =true;
       return;
   }
   
   //连接不上服务器,就创建一个
    server =new QLocalServer(this);
   connect(server, SIGNAL(newConnection()), this,SLOT(newLocalConnection()));
   if(server->listen(serverName))
   {
      //防止程序崩溃时,残留进程服务,移除之
       if(server->serverError()== QAbstractSocket::AddressInUseError &&QFile::exists(server->serverName()))
       {
         QFile::remove(server->serverName());
          server->listen(serverName);
       }
   }
}

voidMainWidget::newLocalConnection()
{
   QLocalSocket *socket =server->nextPendingConnection();
   if(!socket)
       return;
   socket->waitForReadyRead(1000);
    deletesocket;
}

bool MainWidget::isRunning()
{
    returnis_running;

main.cpp中:
MainWidget main_widget;
if(!main_widget.isRunning())
{
   main_widget.showNormal();
   main_widget.raise();
   main_widget.activateWindow();
   
    returnapp.exec();
}

1、创建一个QLoaclSocket,连接服务器
2、创建一个QLocalServer,并监听连接
3、启动应用程序之间,检查有多少个连接,如果至少有一个,意味着打开了一个应用程序,则不再打开另一个。

二:使用共享内存

(1)QSharedMemory 
   方式:先创建一个共享内存,然后在每一个应用程序开始运行之前进行检查是否可以创建一个具有相同unique_id的共享内存,如果不能,则表示创建了实例正在运行。
QSharedMemory shared_memory;
shared_memory.setKey(unique_id);
if(shared_memory.attach())
{
    return0;
}
if(shared_memory.create(1))
{
   MainWidget main_widget;
   main_widget.showNormal();
   main_widget.raise();
   main_widget.activateWindow();
    returnapp.exec();
}
QSharedMemory实现的单程序运行,当运行环境是UNIX时,并且程序不幸崩溃,会导致共享内存无法释放,从而无法重新运行程序!故退出不能使用exit,而需要使用qApp->quit()。
测试时可采用:
#ps -ef | grep test查出程序进程号(若为6919)
#ipcs -m -p查看进程的共享内存
#ipcs -m -p | grep 6919 若程序意外中断,可以查询到该共享内存仍然存在,读取shmid号(第一行id)
#ipcrm -m 15826976即可删除共享内存
参考图:
Qt运行一个实例进程-3种方式简介_第1张图片ca
如果无法知道进程的进程号,则只能根据新进程号推测原来的进程号,然后删除留下的共享内存。
(2)QSystemSemaphore 
//确保只运行一次 
QSystemSemaphore semaphore("ProgramKey",1, QSystemSemaphore::Open);
semaphore.acquire();
//在临界区操作共享内存SharedMemory 
QSharedMemory memory("Program");//全局对象名 
if(!memory.create(1)) //如果全局对象存在则提示退出
{
   QMessageBox::information(0, "Tip", "Program hasbeen running!");
   semaphore.release();
    return0;
semaphore.release();

三:使用QtSingleApplication

       官方发布的有源码,直接下载就可以使用。至于前两种方式在unix下如果程序崩掉内存不释放会出问题。注意QtSingleApplication会在/tmp目录下生成lock文件,若把/tmp变为只读的,就无法运行程序了。
       QSingleApplication位于qt-solution里面,并不包含在Qt库中,遵循 LGPL 协议。参考GitHub:https://github.com/qtproject/qt-solutions/tree/master/qtsingleapplication。
      参考:Qt-Single App Instance:http://berenger.eu/blog/c-qt-singleapplication-single-app-instance/和Replacement of QSingleApplication for Qt5:https://github.com/itay-grudev/SingleApplication。
四、网络代码,写一个QSingleApplication类,来实现Qt程序的单例化(参考)
方案一:使用Qt中的QSharedMemory,QLocalServer和QLocalSocket实现(不过需要在你的.pro里加上QT += network)
// "single_application.h"
#ifndef SINGLE_APPLICATION_H
#define SINGLE_APPLICATION_H
#include 
#include 
#include 
class SingleApplication : public QApplication
{
	Q_OBJECT
public:
	SingleApplication(int &argc, char *argv[], const QString uniqueKey);
	bool isRunning();
	bool sendMessage(const QString &message);
public slots:
	void receiveMessage();
signals:
	void messageAvailable(QString message);
private:
	bool _isRunning;
	QString _uniqueKey;
	QSharedMemory sharedMemory;
	QLocalServer *localServer;
	static const int timeout = 1000;
};
#endif // SINGLE_APPLICATION_H
// "single_application.cpp"
#include 
#include "single_application.h"

SingleApplication::SingleApplication(int &argc, char *argv[], const QString uniqueKey) : QApplication(argc, argv), _uniqueKey(uniqueKey)

{
	sharedMemory.setKey(_uniqueKey);
	if (sharedMemory.attach())
		_isRunning = true;
	else
	{
		_isRunning = false;
		// create shared memory.
		if (!sharedMemory.create(1))
		{
			qDebug("Unable to create single instance.");
			return;
		}

		// create local server and listen to incomming messages from other instances.
		localServer = new QLocalServer(this);
		connect(localServer, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
		localServer->listen(_uniqueKey);
	}
}

// public slots.
void SingleApplication::receiveMessage()
{
	QLocalSocket *localSocket = localServer->nextPendingConnection();
	if (!localSocket->waitForReadyRead(timeout))
	{
		qDebug(localSocket->errorString().toLatin1());
		return;
	}

	QByteArray byteArray = localSocket->readAll();
	QString message = QString::fromUtf8(byteArray.constData());
	emit messageAvailable(message);
	localSocket->disconnectFromServer();
}

// public functions.
bool SingleApplication::isRunning()
{
	return _isRunning;
}

bool SingleApplication::sendMessage(const QString &message)
{
	if (!_isRunning)
		return false;
	QLocalSocket localSocket(this);
	localSocket.connectToServer(_uniqueKey, QIODevice::WriteOnly);
	if (!localSocket.waitForConnected(timeout))
	{
		qDebug(localSocket.errorString().toLatin1());
		return false;
	}

	localSocket.write(message.toUtf8());
	if (!localSocket.waitForBytesWritten(timeout))
	{
		qDebug(localSocket.errorString().toLatin1());
		return false;
	}

	localSocket.disconnectFromServer();
	return true;

方案二:使用Qt中的QSharedMemory,和QTimert实现,别的也没翻译,还是直接来代码吧:

// "single_application.h"
#ifndef SINGLE_APPLICATION_H
#define SINGLE_APPLICATION_H
#include 
#include 
class SingleApplication : public QApplication
{
	Q_OBJECT
public:
	SingleApplication(int &argc, char *argv[], const QString uniqueKey);
	bool isRunning();
	bool sendMessage(const QString &message);
public slots:
	void checkForMessage();
signals:
	void messageAvailable(QString message);
private:
	bool _isRunning;
	QSharedMemory sharedMemory;
};
#endif // SINGLE_APPLICATION_H
// "single_application.cpp"
#include 
#include 
#include "single_application.h"

SingleApplication::SingleApplication(int &argc, char *argv[], const QString uniqueKey) : QApplication(argc, argv)
{
	sharedMemory.setKey(uniqueKey);
	if (sharedMemory.attach())
		_isRunning = true;
	else
	{
		_isRunning = false;
		// attach data to shared memory.
		QByteArray byteArray("0"); // default value to note that no message is available.
		if (!sharedMemory.create(byteArray.size()))
		{
			qDebug("Unable to create single instance.");
			return;
		}
		sharedMemory.lock();
		char *to = (char*)sharedMemory.data();
		const char *from = byteArray.data();
		memcpy(to, from, qMin(sharedMemory.size(), byteArray.size()));
		sharedMemory.unlock();

                // start checking for messages of other instances.
		QTimer *timer = new QTimer(this);
		connect(timer, SIGNAL(timeout()), this, SLOT(checkForMessage()));
		timer->start(1000);
	}
}

// public slots.
void SingleApplication::checkForMessage()
{
	sharedMemory.lock();
	QByteArray byteArray = QByteArray((char*)sharedMemory.constData(), sharedMemory.size());
	sharedMemory.unlock();
	if (byteArray.left(1) == "0")
		return;
	byteArray.remove(0, 1);
	QString message = QString::fromUtf8(byteArray.constData());
	emit messageAvailable(message);

        // remove message from shared memory.
	byteArray = "0";
	sharedMemory.lock();
	char *to = (char*)sharedMemory.data();
	const char *from = byteArray.data();
	memcpy(to, from, qMin(sharedMemory.size(), byteArray.size()));
	sharedMemory.unlock();
}

// public functions.
bool SingleApplication::isRunning()
{
	return _isRunning;
}

bool SingleApplication::sendMessage(const QString &message)
{
	if (!_isRunning)
		return false;

	QByteArray byteArray("1");
	byteArray.append(message.toUtf8());
	byteArray.append('/0'); // < should be as char here, not a string!
	sharedMemory.lock();
	char *to = (char*)sharedMemory.data();
	const char *from = byteArray.data();
	memcpy(to, from, qMin(sharedMemory.size(), byteArray.size()));
	sharedMemory.unlock();
	return true;
}

使用:

// "main.cpp"
#include "single_application.h"
int main(int argc, char *argv[])
{
	SingleApplication app(argc, argv, "some unique key string");
	if (app.isRunning())
	{
		app.sendMessage("message from other instance.");
		return 0;
	}
	MainWindow *mainWindow = new MainWindow();

        // connect message queue to the main window.
	QObject::connect(&app, SIGNAL(messageAvailable(QString)), mainWindow, SLOT(receiveMessage(QString)));

        // show mainwindow.
	mainWindow->show();
	return app.exec();
}

你可能感兴趣的:(LinuxQt编程)