By Kong-dao Xing
Linux 系统IPC种类:
- 信号
- 管道
- 命名管道
- 信号量
- 消息队列
- 共享内存
- 内存映射文件
- 套接字
DBus 概念
总线
持久化的系统总线(system bus)
- 系统开机引导时就启动, system bus 由操作系统和后台进程使用, 安全性好。
会话总线(session bus)
- 用户登录时启动
在指定的对象中调用指定的方法,需要知道的参数如下:
Address -> Bus Name -> Path -> Interface -> Method
DBus 库
1. 函数库libdbus,用于两个应用程序互相联系和交互消息。 2. 一个基于libdbus构造的消息总线守护进程(dbus-daemon),可同时与多个应用程序相连, 并能把来自一个应用程序的消息路由到0或者多个其他程序。 3. 基于特定应用程序框架的封装库或捆绑(wrapper libraries or bindings )。 例如,libdbus-glib和libdbus-qt,还有绑定在其他语言, 例如 Python 的。大多数开发者都是使用这些封装库的API, 因为它们简化了D-Bus编程细节。libdbus被有意设计成为更高层次绑定的底层后端(low-levelbackend )。 大部分libdbus的 API仅仅是为了用来实现绑定。
优点
低延迟:DBus一开始就是用来设计成避免来回传递和允许异步操作的。因此虽然在Application和Daemon之间是通过socket实现的,但是又去掉了socket的循环等待,保证了操作的实时高效。
低开销:DBus使用一个二进制的协议,不需要转化成像XML这样的文本格式。因为DBus是主要用来机器内部的IPC,而不是为了网络上的IPC机制而准备的.所以它才能够在本机内部达到最优效果。
高可用性:DBus是基于消息机制而不是字节流机制。它能自动管理一大堆困难的IPC问题。同样的,DBus库被设计来让 程序员 能够使用他们已经写好的代码。而不会让他们放弃已经写好的代码,被迫通过学习新的IPC机制来根据新的IPC特性重写这些代码。
绝大部分的 linux 桌面环境都使用的dbus作为进程间通信。 比如:GNOME 和KDE
支持golang, c/c++, python 语言
D-Bus进程通信简单框架
D-Bus进程通信简单框架
Create DBus
获取system bus
QDBusConnection systemBus = QDBusConnection::systemBus();
获取session bus
QDBusConnection sessionBus = QDBusConnection::sessionBus();
注册服务
bool
QDBusConnection::registerService (
const
QString & serviceName )
注册对象接口
bool QDBusConnection::registerObject (const QString & path, QObject * object, RegisterOptions options = ExportAdaptors ) //常用Option选项 QDBusConnection::ExportAdaptors QDBusConnection::ExportNonScriptableSlots QDBusConnection::ExportNonScriptableSignals QDBusConnection::ExportNonScriptableProperties QDBusConnection::ExportNonScriptableInvokables// Q_INVOKABLE QDBusConnection::ExportAllContents = QDBusConnection::ExportNonScriptableSlots|QDBusConnection::ExportNonScriptableSignals |QDBusConnection::ExportNonScriptableInvokables|QDBusConnection::ExportScriptableProperties
例子:
Dbus Server
// person.h #include <QObject> class Person :public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface","com.brion.interface") public: explicit Person(QObject *parent = 0); signals: void nameChanged(QString); void ageChanged(int); public slots: QString name()const {return m_name; } // can't be reference void setName(QString name) { m_name = name; } int age()const {return m_age; } void setAge(int age) { m_age = age; } private: QString m_name; int m_age; }; // main.cpp #include <QtDBus/QDBusConnection> #include <person.h> int main(int argc,char *argv[]) { QApplication a(argc, argv); QDBusConnection sessionBus = QDBusConnection::sessionBus(); if (sessionBus.registerService("com.brion.service")) { sessionBus.registerObject("/",new Person(), QDBusConnection::ExportAllContents); } return a.exec(); }
d-feet 查看dbus 服务
DBus Client
// main.cpp #include <QCoreApplication> #include <QDBusConnection> #include <QDBusInterface> #include <QDBusReply> #include <QDebug> int main(int argc,char *argv[]) { QCoreApplication a(argc, argv); QDBusInterface interface("com.brion.service","/","com.brion.interface"); interface.call("setName","Brion"); QDBusReply<QString> reply = interface.call("name"); if (reply.isValid()) { qDebug()<<"name = "<<reply.value(); } interface.call("setName","ASML"); reply = interface.call("name"); if (reply.isValid()) { qDebug()<<"name = "<<reply.value(); } return a.exec(); }
输出:
name =
"Brion"
name =
"ASML"
客户端调用服务端的函数
方式一
// 传参数 QDBusMessage msg = QDBusMessage::createMethodCall("com.brion.service", "/","com.brion.interface","setName"); msg << QString("Brion"); QDBusMessage response = QDBusConnection::sessionBus().call(msg); // 获取返回值 QDBusMessage msg = QDBusMessage::createMethodCall("com.brion.service", "/","com.brion.interface","name"); QDBusMessage response = QDBusConnection::sessionBus().call(msg); // 判断Method 是否被正确返回 if(response.type() == QDBusMessage::ReplyMessage) { // QDBusMessage的arguments不仅可以用来存储发送的参数,也用来存储返回值 // 这里取得 name 的返回值 QString name= response.arguments().takeFirst().toString(); }
方式二
QDBusInterface interface("com.brion.service","/", "com.brion.interface", QDBusConnection::sessionBus()); if(!interface.isValid()) { qDebug() << qPrintable(QDBusConnection::sessionBus().lastError().message()); exit(1); } // 调用 setName, interface.call("setName","Brion"); // 调用 name, QDBusReply<QString> reply = interface.call("name"); if(reply.isValid()) { QString value = reply.value(); qDebug()<<"value = "<<value ; }
方式三: 异步调用
QDBusPendingCall async = interface->asyncCall("setName","Brion"); // async.waitForFinished () QDBusPendingCallWatcher *watcher =new QDBusPendingCallWatcher(async,this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*))); void MyClass::callFinishedSlot(QDBusPendingCallWatcher *call) { QDBusPendingReply<QString> reply = *call; if (!reply.isError()) { QString name= reply.argumentAt<0>(); qDebug()<<"name = "<<name; } call->deleteLater(); }
客户端接收服务端信号
方式一:
QDBusConnection::sessionBus().connect("com.brion.service","/", "com.brion.interface", "ageChanged",this, SLOT(onAgeChanged(int)));
方式二:
QDBusInterface *interface =new QDBusInterface ("com.brion.service","/", "com.brion.interface",DBusConnection::sessionBus()); QObject::connect(&interface, SIGNAL(ageChanged(int)), object, SLOT(onAgeChanged(int)));
QtDBus 默认支持的数据类型
Qt type |
D-Bus equivalent type |
---|---|
Qt type |
D-Bus equivalent type |
uchar | BYTE |
bool | BOOLEAN |
short | INT16 |
ushort | UINT16 |
int | INT32 |
uint | UINT32 |
qlonglong | INT64 |
qulonglong | UINT64 |
double | DOUBLE |
QString | STRING |
QDBusVariant | VARIANT |
QDBusObjectPath | OBJECT_PATH |
QDBusSignature | SIGNATURE |
同时支持
QStringList, QByteArray
自定义类型
方式一:
struct MyStructure { int count; QString name; }; Q_DECLARE_METATYPE(MyStructure) // 服务端和客户端都要重载 QDBusArgument &operator<<(QDBusArgument &argument,const MyStructure &mystruct) { argument.beginStructure(); argument << mystruct.count << mystruct.name; argument.endStructure(); return argument; } // Retrieve the MyStructure data from the D-Bus argument const QDBusArgument &operator>>(const QDBusArgument &argument, MyStructure &mystruct) { argument.beginStructure(); argument >> mystruct.count >> mystruct.name; argument.endStructure(); return argument; } qRegisterMetaType<MyStructure>("MyStructure"); qDBusRegisterMetaType<MyStructure>();
方式二:
利用QByteArray实现自定义类型
class MyClass { private: int count; QString name; } QDataStream & operator<< (QDataStream& stream,const MyClass& myclass) { stream<<myclass.count; stream<<myclass.name; } QDataStream & operator>> (QDataStream& stream,const MyClass& myclass) { stream>>myclass.count; stream>>myclass.name; }
服务端先把数据写入QByteArray。 客户端通过QDataStream把数据从QByteArray读出
编写Adaptor
如果注册对象时,使用QDBusConnection::ExportAllContents, 会导致很多的接口都暴露给用户。 为此, 可以编写Adaptor来控制接口
// adaptor.h #include <QDBusAbstractAdaptor> #include <QDebug> class Adaptor :public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface","com.brion.interface") Q_CLASSINFO("D-Bus Introspection","" "<interface name=\"com.brion.interface\">\n" " <method name=\"setAge\">\n" " <arg type=\"i\" direction=\"in\"/>" " </method>\n" " <signal name=\"ageChanged\">\n" " <arg type=\"i\" direction=\"out\"/>" " </signal>" "</interface>\n" "") public: Adaptor::Adaptor(QObject* parent = 0) : QDBusAbstractAdaptor(parent) { // 是否转发signals setAutoRelaySignals(true); } signals: void ageChanged(int age); public slots: void setAge(int age) { QMetaObject::invokeMethod(parent(),"setAge", Q_ARG(int, age)); } }; // person.h #include <QObject> class Person :public QObject { Q_OBJECT public: Person::Person(QObject *parent) : QObject(parent) { m_age = 0; new Adaptor(this); } signals: void nameChanged(QString); void ageChanged(int); public slots: QString name()const {return m_name; } void setName(QString name) { m_name = name; } int age()const {return m_age; } void setAge(int age) { m_age = age; emit ageChanged(m_age); } private: QString m_name; int m_age; };
XML数据类型定义
基本类型
type |
code |
---|---|
type |
code |
BYTE | y |
BOOLEAN | b |
INT16 | n |
UINT16 | q |
INT32 | i |
UINT32 | u |
INT64 | x |
UINT64 | t |
DOUBLE | d |
STRING | s |
VARIANT | v |
OBJECT_PATH | o |
void setAge(int age)
<method name=\"setAge\"> <arg type=\"i\" direction=\"in\"/> // in 传参 </method>
int age() const
<method name=\"age\"> <arg type=\"i\" direction=\"out\"/> // out 返回值 </method>
void setName(QString name)
<method name=\"setName\"> <arg type=\"s\" direction=\"in\"/> </method>
void setNames(QStringList names)
<method name=\"setNames\"> <arg type=\"as\" direction=\"in\"/> </method>
void setNames(QByteArray ba)
<method name=\"setNames\"> <arg type=\"ay\" direction=\"in\"/> </method>
自定义类型
类和结构体, 不允许空结构体
struct MyStruct { int key; QString value; }
void setCustom(MyStruct my)
<method name=\"setCustom\"> <arg type=\"(is)\" direction=\"in\"/> </method>
void setCustoms(QList<MyStruct> mystructs)
<method name=\"setCustoms\"> <arg type=\"a(is)\" direction=\"in\"/> </method>
struct
MyStruct
{
QMap<QString, QVariant> maps;
}
void setCustom(MyStruct my)
<method name=\"setCustom\"> <arg type=\"(a{sv})\" direction=\"in\"/> </method>
键值队
void setDict(QMap<int, QString> dict);
<method name=\"setDict\"> <arg type=\"a{is}\" direction=\"in\"/> </method>
权限控制
通过配置文件来实现权限控制。
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <type>session/system</type> <policy context="default"> <deny send_destination="com.brion.service"/> </policy> <policy user="service"> <!-- Only service user can own the "com.brion.service" service --> <allow own="com.brion.service"/> <allow send_destination="com.brion.service"/> </policy> <policy user="system"> <allow send_destination="com.brion.service"/> </policy> <policy group="systemapps"> <allow send_destination="com.brion.service" send_interface="com.brion.interface" send_member="setAge" send_path="/" send_type="method_call"/> <allow send_destination="com.brion.service" send_interface="com.brion.interface" send_member="ageChanged" send_path="/" send_type="signal"/> <deny send_destination="com.brion.service" send_interface="com.brion.service" send_member="age" send_path="/" send_type="method_call"/> <deny send_destination="com.brion.service" send_interface="com.brion.interface" send_member="nameChanged" send_path="/" send_type="signal"/> </policy> <policy at_console="true"> <allow send_destination="xxx.xx.xx"/> <allow send_interface="xxx.xx.xx"/> </policy> </busconfig>
所有 context=”default” 的策略被应用
所有 group=”connection’s user’s group” 的策略以不定的顺序被应用
所有 user=”connection’s auth user” 的策略以不定顺序被应用
所有 at_console=”true” 的策略被应用
所有 at_console=”false” 的策略被应用
所有 context=”mandatory” 的策略被应用
后应用的策略会覆盖前面的策略。
dbus 常用命令
dbus-send
调用函数
dbus-send --session --type=method_call --dest=com.brion.service / com.brion.interface.setName "string:Brion"
发送信号
dbus-send --session --type=signal --dest=com.brion.service / com.brion.interface.ageChanged int32:10000
dbus-monitor
监听dbus-daemon的行为
手动启动dbus-daemon
DBUS_VERBOSE=1 dbus-daemon --session --print-address
启动后会得到一个地址
unix:abstract=/tmp/dbus-YcjSNNPJHg,guid=18b385acdbd58611ffd3196b4beb69f0
设置环境变量 DBUS_SESSION_BUS_ADDRESS
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-YcjSNNPJHg,guid=18b385acdbd58611ffd3196b4beb69f0
再启动dbus server 和dbus client 都会用这个dbus-daemon 来通信。
附:示例代码:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Data Mining
Bing Liu / Springer / 2011-6-26 / CAD 61.50
Web mining aims to discover useful information and knowledge from Web hyperlinks, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is not purely an ......一起来看看 《Web Data Mining》 这本书的介绍吧!