使用到QDBus一般就是用于进程通信。QT进程通信的几大方法中,QDBus可以实现不同进程间信号槽的连接,而其它几中方法QSharedMemory(共享内存),QProcess(进程),QLocalSocket(本地通信),QTcpSocket(tcp通信)中都无法做到这点,至于详细原因,这里不做细讲。
使用QDBus,常用的几个类,分别是QDBusMessage(用于消息发送)、QDBusInterface(用于消息发送)、QDBusConnection(用于连接、注册、发送)。
在通信时会通过总线来进行,这里支持系统总线和回话总线。
//system bus(系统总线),用于系统(Linux)和用户程序之间进行通信和消息的传递;
//session bus(回话总线),用于桌面(GNOME, KDE等)用户程序之间进行通信。
服务器流程:1、获取连接。2、通过连接注册服务器名。3、通过连接注册服务器对象路径。4、根据需要连接客户端的槽函数。5、发送消息。
直接上代码,注释中已经全部说明了。
#include "mainwindow.h"
#include <QApplication>
#include <QDBusConnection>
#include <QMessageBox>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//system bus(系统总线),用于系统(Linux)和用户程序之间进行通信和消息的传递;
//session bus(回话总线),用于桌面(GNOME, KDE等)用户程序之间进行通信。
QDBusConnection dbus = QDBusConnection::sessionBus();
// 服务器名:com.widget.test
if(!dbus.registerService("com.mydbus.server"))
{
QMessageBox::information(0,"error","dbus registerservice fail");
return -1;
}
MainWindow w;
/* 服务器对象路径:/test/objects
QDBusConnection::RegisterOption::ExportAllSlots 对应的所有操函数必须为public权限
*/
dbus.registerObject("/test/objects",&w,QDBusConnection::RegisterOption::ExportAllSlots);
w.show();
return a.exec();
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusInterface>
class MainWindow : public QMainWindow
{
Q_OBJECT
// DBus固定字段 D-Bus Interface
// 服务器接口:com.service.interface,
Q_CLASSINFO("D-Bus Interface","com.service.interface")
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
int showmin();
int shownormal();
void slotsend(bool flag);
private slots:
void service_get(QString name, int num);
private:
QPushButton* m_sendbtn;
QTextEdit* m_readedit;
QLineEdit* m_sendedit;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "mainwindow.h"
#include <QApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->resize(300,300);
this->setWindowTitle("mydbus server");
QVBoxLayout* lay = new QVBoxLayout(this);
m_sendbtn = new QPushButton("发送",this);
m_sendedit = new QLineEdit(this);
m_readedit = new QTextEdit(this);
lay->addWidget(m_sendedit);
lay->addWidget(m_sendbtn);
lay->addWidget(m_readedit);
QWidget* w = new QWidget(this);
this->setCentralWidget(w);
w->setLayout(lay);
connect(m_sendbtn,SIGNAL(clicked(bool)),this,SLOT(slotsend(bool)));
/*
* 服务器名:null
* 服务器临时路径:/home/yjd/testpath
* 服务器临时接口:com.interface
* 自定义的信号:send_to_server
*/
QDBusConnection::sessionBus().connect("","/home/yjd/testpath","com.interface","send_to_server",this,SLOT(service_get(QString,int)));
}
MainWindow::~MainWindow()
{
}
void MainWindow::service_get(QString name,int num)
{
m_readedit->append(QString("接收:%1-%2").arg(name).arg(num));
}
void MainWindow::slotsend(bool flag)
{
/*
* 服务器临时路径:/home/yjd/testpath
* 服务器临时接口:com.interface
* 自定义的信号:send_to_server
*/
QDBusMessage msg = QDBusMessage::createSignal("/home/yjd/testpath","com.interface","send_to_control");
msg<<m_sendedit->text()<<888;
QDBusConnection::sessionBus().send(msg);
m_readedit->append(QString("参数:%1 发送:%2").arg(flag).arg(m_sendedit->text()));
}
int MainWindow::showmin()
{
showMinimized();
m_readedit->append("最小化");
return 2021;
}
int MainWindow::shownormal()
{
showNormal();
hide();
show();
m_readedit->append("恢复正常");
return 2020;
}
客户端流程:1、根据需要链接槽函数。2、发送信号。3、根据需要也可以发送服务端注册的槽函数。
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtWidgets>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusInterface>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void control(QString method);
private slots:
void service_get(QString name, int num);
void slotsend();
void slotnormal();
void slotmin();
void slottest();
private:
QPushButton* m_sendbtn;
QPushButton* m_minbtn;
QPushButton* m_normalbtn;
QPushButton* m_testbtn;
QTextEdit* m_readedit;
QLineEdit* m_sendedit;
};
#endif // WIDGET_H
#include "widget.h"
#include <QApplication>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(300,400);
this->setWindowTitle("mydbus-control");
QVBoxLayout* lay = new QVBoxLayout(this);
m_sendbtn = new QPushButton("发送",this);
m_minbtn = new QPushButton("最小化",this);
m_normalbtn = new QPushButton("正常",this);
m_testbtn = new QPushButton("测试",this);
m_sendedit = new QLineEdit(this);
m_readedit = new QTextEdit(this);
lay->addWidget(m_minbtn);
lay->addWidget(m_normalbtn);
lay->addWidget(m_testbtn);
lay->addWidget(m_sendedit);
lay->addWidget(m_sendbtn);
lay->addWidget(m_readedit);
this->setLayout(lay);
connect(m_minbtn,SIGNAL(clicked()),this,SLOT(slotmin()));
connect(m_normalbtn,SIGNAL(clicked()),this,SLOT(slotnormal()));
connect(m_testbtn,SIGNAL(clicked()),this,SLOT(slottest()));
connect(m_sendbtn,SIGNAL(clicked()),this,SLOT(slotsend()));
/*
* 服务器名:null
* 服务器临时路径:/home/yjd/testpath
* 服务器临时接口:com.interface
* 自定义的信号:send_to_server
*/
QDBusConnection::sessionBus().connect("","/home/yjd/testpath","com.interface","send_to_control",this,SLOT(service_get(QString,int)));
}
Widget::~Widget()
{
}
void Widget::service_get(QString name,int num)
{
m_readedit->append(QString("接收:%1-%2").arg(name).arg(num));
}
void Widget::slotsend()
{
/*
* 服务器临时路径:/home/yjd/testpath
* 服务器临时接口:com.interface
* 自定义的信号:send_to_server
*/
QDBusMessage msg = QDBusMessage::createSignal("/home/yjd/testpath","com.interface","send_to_server");
msg<<m_sendedit->text()<<666;
QDBusConnection::sessionBus().send(msg);
m_readedit->append(QString("发送:%1").arg(m_sendedit->text()));
}
void Widget::slotmin()
{
control("showmin"); //名称必须与服务端的槽函数名称一样
}
void Widget::slotnormal()
{
control("shownormal"); //名称必须与服务端的槽函数名称一样
}
void Widget::slottest()
{
control("slotsend"); //名称必须与服务端的槽函数名称一样
}
void Widget::control(QString method)
{
bool flag = true;
/*
* 注册的服务器名称:com.widget.test
* 注册的服务器对象路径:/test/objects
* 注册的服务器接口:com.service.interface,
* 方法名称为:method
*/
#if 1
//方法一 绑定方法和服务端注册的相关接口
QDBusMessage msg = QDBusMessage::createMethodCall("com.mydbus.server","/test/objects","com.service.interface",method);
if (method == "slotsend")
msg<<flag; //有参数时,添加参数
QDBusMessage res = QDBusConnection::sessionBus().call(msg); //发送个服务端
#else
//方法二 在接口interface中设置服务端注册的相关接口,然后接口绑定方法。
QDBusInterface interface("com.mydbus.server","/test/objects","com.service.interface",QDBusConnection::sessionBus());
if (!interface.isValid())
{
QMessageBox::information(this,"error","dbus interface fail");
return;
}
QDBusMessage res;
if (method == "slotsend")
res = interface.call(method,flag); // 有参数
else
res = interface.call(method); // 无参数
#endif
if (res.type() == QDBusMessage::ReplyMessage)
{
//从返回参数获取返回值
if (res.arguments().size() > 0)
{
int value = res.arguments().takeFirst().toInt();
m_readedit->append(QString("%1 返回值:%2").arg(method).arg(value));
}
else
m_readedit->append(QString("%1 返回值:null").arg(method));
}
else
{
m_readedit->append(QString("%1 返回值失败").arg(method));
}
}