进程间通讯方式
Qt 提供了四种进程间通信的方式:
使用共享内存(shared memory)交互:这是Qt 提供的一种各个平台均有支持的进程间交互的方式。
TCP/IP:其基本思想就是将同一机器上面的两个进程一个当做服务器,一个当做客户端,二者通过网络协议进行交互。除了两个进程是在同一台机器上,这种交互方式与普通的C/S 程序没有本质区别。Qt 提供了QNetworkAccessManager 对此进行支持。
D-Bus:freedesktop 组织开发的一种低开销、低延迟的IPC 实现。Qt 提供了QtDBus模块,把信号槽机制扩展到进程级别(因此我们前面强调是“普通的”信号槽机制无法实现IPC),使得开发者可以在一个进程中发出信号,由其它进程的槽函数响应信号。
QCOP(Qt COmmunication Protocol):QCOP 是Qt 内部的一种通信协议,用于不同的客户端之间在同一地址空间内部或者不同的进程之间的通信。目前,这种机制只用于Qt for Embedded Linux 版本。进程之间通讯方式种类繁多,在Qt 下,一般使用TCP/IP 比较简单和方便。
使用原因
就难易程度,使用习惯及速度方面,进程间通讯,TCP无疑是很好的。
某次一个相机项目中,需要同时打开使用n个相机,单个进程实现需要对相机提供的SDK 进行很大的改动,所以采用了进程间通讯的方式来完成任务。
首先采用了TCP通讯,所有收发命令都做好后,进行测试,当开启相机实时预览的时候,TCP出现了“假死”,即这边发送消息,另一边怎么都没反应,使用wireshark ,抓包发现,一旦发送了实时预览命令开启预览后,后面无论发送什么消息。wireshark 都没有数据包,并且最终信息提示 TCP 出现了问题(图片信息及出现的问题错误代码,现在没有了,期间电脑固态坏了,数据没了),这个错误问题,经搜索引擎最终没能解决(这个问题还是没有探索出来)。
问题没能解决,只能更换方案。
原文链接:https://blog.csdn.net/dxa572862121/article/details/104994436
共享内存(Shared Memory)是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。共享内存实际就是内存映射的一种特殊情况。在《windows核心编程》写道:
在Windows中,在同一台机器上数据共享的最底层机制就是内存映射文件。 这种数据共享机制是通过让两个或多个进程映射同一个文件映射对象的视图来实现,意味着在进程间共享相同的物理存储页面。对多个进程共享同一个文件映射对象来说,所有进程使用的文件映射对象的名称必须完全相同。
共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,其它进程打开该文件映射对象就可以访问该内存块,这样每个进程都可以读取同一份数据,从而实现进程通信。因为是通过内存操作实现通信,因此是一种最高效的数据交换方法。由于共享内存是用文件映射实现的,所以它也有较好的安全性,也只能运行于同一计算机上的进程之间。
Qt提供了QSharedMemory类和QSystemSemaphore类,QSharedMemory可以访问共享内存区域,以及多线程和进程的共享内存区域。而QSystemSemaphore类用于访问系统共享资源,以实现独立进程间的通信。
原文链接:https://blog.csdn.net/Sakuya__/article/details/89519412
(一)向共享内存中提供数据的一方:
1,定义QSharedMemory shareMemory,并设置标志名shareMemory.setKey(),例如shareMemory.setKey("shareimg");
2,将共享内存与主进程分离 shareMemory.detach();
3,创建共享内存 shareMemory.create();
4,将共享内存上锁shareMemory.lock();
5,将进程中要共享的数据拷贝到共享内存中;
6,将共享内存解锁shareMemory.unlock();
新建项目1,代码:
write.h
#ifndef WRITE_H
#define WRITE_H
#include <QWidget>
#include <QSharedMemory>
QT_BEGIN_NAMESPACE
namespace Ui { class write; }
QT_END_NAMESPACE
class write : public QWidget
{
Q_OBJECT
public:
write(QWidget *parent = nullptr);
~write();
private slots:
void on_pushButton_clicked();
private:
Ui::write *ui;
QSharedMemory sharedmomory;
};
#endif // WRITE_H
write.cpp
#include "write.h"
#include "ui_write.h"
#include<QDebug>
write::write(QWidget *parent)
: QWidget(parent)
, ui(new Ui::write)
{
ui->setupUi(this);
sharedmomory.setKey("My_Shared_Memory");//
}
write::~write()
{
delete ui;
}
void write::on_pushButton_clicked()
{
if(sharedmomory.isAttached())//如果共享内存被绑定,则解除绑定
{
sharedmomory.detach();
}
if(!sharedmomory.create(100,QSharedMemory::ReadWrite)) //bool create(int size, AccessMode mode = ReadWrite);
{
qDebug()<<"failed to create shared momory";
return;
}
sharedmomory.lock(); //共享内存上锁
QByteArray arr=ui->lineEdit->text().toLatin1();//文本转换成QByteArray类型
//void * __cdecl memcpy(void * __restrict__ _Dst,const void * __restrict__ _Src,size_t _Size)
//参数一 拷贝到哪里去 是个地址,参数二 参数的来源 是个地址,参数三 拷贝的大小
memcpy(sharedmomory.data(),arr.data(),(size_t)qMin(sharedmomory.size(),ui->lineEdit->text().size()));
//共享内存的大小与你输入的大小作比较,取出较小的那个
sharedmomory.unlock(); //共享内存锁
}
ui设计器添加控件如图:
(二)从共享内存中取数据的一方:
1,定义QSharedMemory shareMemory,并设置共享内存的标志名shareMemory.setKey()注意设置的要与提供内存共享的一方要一样,本例是shareMemory.setKey("shareimg")。
2,将共享内存上锁shareMemory.lock();
3,将共享内存与主进程绑定shareMemory.attach(),使该进程可以访问共享内存的数据;
4,从共享内存中取数据;
5,使用完后将共享内存解锁shareMemory.unlock(),最后将共享内存与该进程分离shareMemory.detach();
新建项目2,代码:
read.h
#ifndef READ_H
#define READ_H
#include <QWidget>
#include <QSharedMemory>
QT_BEGIN_NAMESPACE
namespace Ui { class read; }
QT_END_NAMESPACE
class read : public QWidget
{
Q_OBJECT
public:
read(QWidget *parent = nullptr);
~read();
private slots:
void on_pushButton_clicked();
private:
Ui::read *ui;
QSharedMemory sharedmomory;
};
#endif // READ_H
read.cpp
#include "read.h"
#include "ui_read.h"
#include<QDebug>
read::read(QWidget *parent)
: QWidget(parent)
, ui(new Ui::read)
{
ui->setupUi(this);
sharedmomory.setKey("My_Shared_Memory");
}
read::~read()
{
delete ui;
}
void read::on_pushButton_clicked()
{
if(!sharedmomory.attach())
{
qDebug()<<"Attach shared momory failed";
return;
}
sharedmomory.lock();
char *arr=new char[sharedmomory.size()]; //开辟出与共享资源同样大小的空间
memcpy(arr,sharedmomory.data(),(size_t)sharedmomory.size());
//将write共享内存sharedmomory开辟出来的内容 拷贝到arr开辟出来的内存空间中
ui->label->setText(QString(arr));//将arr的内容转换为QString类型显示
sharedmomory.unlock();
sharedmomory.detach(); //解除绑定
}
ui设计器添加控件如图:
当从write端向共享内存写入字符串后,在read端就可以独处相应的数据啦
如图: