QLocalSocket 是Qt提供的一个进程与进程之间的通信的方法,在Windows系统上使用管道技术实现。
翻阅了一下微软的MSDN得知管道技术是通过共享内存实现的,创建管道的进程称为pipe server,连接的被称为pipe client,当一个进程往管道中写入信息后,另一个进程就可以在这个管道中读取信息。
扯远了,文章主要记录QLocalServer和QLocalSocket如何使用,然后在实现进程通信的基础上,实现一个程序保证在系统里只有一个实例在运行。
QLocalSocket QLocalServer
使用QLocalServer 时,先调用listen(const QString& name)启动监听服务,调用时需要传入服务端名称,localSocket连接服务端时也是通过这个名称查找到服务端。监听开启后,当有localSocket连接服务端时会发出newConnection()信号。
当已知有localSocket连接服务端时,可以调用nextPendingConnection() 获取请求连接并挂起的localSocket,然后通过socket对象就可以实现信息的读写操作了。
注意:QLocalServer对象在不使用时应该调用close()函数取消监听。
QLocalSocket类继承于QIODevice,所以有write() read() readLine() readAll() 函数可以使用。
使用时调用connectToServer(const QString& name)连接到服务端,可以使用waitForConnected()等待连接成功,默认的连接超时时间时30秒,也可以通过参数传入超时时间。
连接成功之后就可以调用read()和write()函数进行读写了,需要注意的时在读取前最好调用waitForReadyRead()等待信息被写入完成,再读取数据。同样,再写入之后也最后再调用waitForBytesWritten()保证数据被成功写入。这两个函数均可以传入一个超时时间,如果等待超时会返回false。
实现进程通信
了解以上信息之后,实现进程通信就非常简单了,只需要一个进程开启服务端监听,然后另一个进程再使用socket连接服务端,连接成功之后就可以写入/读取消息了。
.h
#include <QObject> #include <QLocalServer> #include <QLocalSocket> class TestProcessCommunication:public QObject { Q_OBJECT public: TestProcessCommunication(); ~TestProcessCommunication(); public slots: void newConnection(); private: QString serverName = "TestPrc"; QLocalServer* server; };
.cpp
#include "testprocesscommunication.h" #include <iostream> TestProcessCommunication::TestProcessCommunication() { //判断是否已有服务端存在 QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(2*1000)) { //如果已存在则发送消息 socket.write("hello world!"); if(socket.waitForBytesWritten()) return; } server = new QLocalServer(); server->listen(serverName); connect(server,SIGNAL(newConnection()),this,SLOT(newConnection())); if(!server->isListening()) std::cerr << "listen failed!" << std::endl; } TestProcessCommunication::~TestProcessCommunication() { server->close(); delete server; } void TestProcessCommunication::newConnection() { auto socket = server->nextPendingConnection(); if(!socket) return; if(socket->waitForReadyRead()) { auto msg = QString(socket->readAll()); std::cerr << "receive msg: " << msg.toStdString() << std::endl; } }
在两个进程中都创建一个TestProcessCommunication对象,第一个创建的对象就可以收到消息了。
注意:再同一个进程中同时创建两个对象,会因为消息等待的原因导致有时候获取不到信息,测试的时候最好是在两个进程中进行测试。(两个线程没有尝试)
程序实现单个实例运行
某些应用场景中,会希望程序只有一个实例在运行,但是一个普通的程序,在windows系统中每启动一次都会有一个实例在系统中运行。
这个时候可以在程序运行的时候尝试连接程序的localServer,如果连接失败,说明系统中还没有程序的实例,那么启动一个localServer监听,然后正常启动程序。如果连接成功则说明已经有实例在运行,那么直接退出程序。
如果当前启动的程序是带着任务启动的(如打开文件),但是系统中已存在程序实例,那么可以通过localSocket将任务信息发送给已经运行的实例,由它来完成任务,这样就既能保证系统中只有一个程序实例运行,也能保证不会忽略掉用户的一些操作。
文章评论