Qt Dbus Communication
What is a Dbus?
Dbus is an inter-process communication system. It allows two individual
processes to communicate with each other. It is available in Linux based and
Unix based systems.
How does qt Support
dbus communication?
Qt provides a
module called QtDBus module. It is a
Unix-only library which can be used to perform IPCs (Inter Process
Communication)
However if you want
two processes to start communicating with each using dbus certain initial setup has to be done. And the two communicating
processes will be obligated to follow a contract.
The contract is
enforced by a user defined interface.
Let’s try and have
two processes communicate with each other using dbus.
Here in our example
let’s implement a client and server to illustrate dbus communication.
Before we create the server process, the server process should provide certain services which can be accessed by clients.
Before we create the server process, the server process should provide certain services which can be accessed by clients.
This service is
defined by the user defined interface. So our first job would be to define an
interface.
We shall define an
interface using an xml document; later the xml file shall be converted to
regular C++ class using a tool called “qbusxml2cpp”
Create an xml file
and name it as “com.inter.Demo.xml”.
The naming of the xml file is a dotted filename; it is similar to a network
address of a host computer. The dotted sequence convention has been followed to
name the interface.
The xml File should contain the following:
<node>
<interface
name="com.inter.Demo">
<method name="AddTwoNumbers">
<arg name="expr1" type="s"
direction="in" />
<arg name="expr2" type="s"
direction="in" />
</method>
<method name="Display"/>
<signal name="MySignal">
<arg name="eventkind" type="s"
directon="out" />
</signal>
</interface>
</node>
com.inter.Demo.xml
The above displayed xml file tells that the name of the interface is “com.inter.Demo” (the one which was
earlier told to enforce a contract) It contains two slots (basically methods)
and a signal.
The name of one of the methods is “AddTwoNumbers”
it takes two arguments. The type=”s”
specifies the argument type is a string, the direction=”in” specifies it as an input parameter.
The other method defined in this interface is “display” it takes no arguments or whatsoever.
We have a signal called “MySignal”
that has one parameter. This can be used when this signal is being emitted
from a slot or any method.
Once, the interface file in xml is written we can generate the adaptor classes
(server related C++ files) and client proxies (Client related C++ files) using
the “qdbusxml2cpp” tool.
Now, Lets create the adaptor class from the “com.inter.Demo.xml” file
It can be created using the following command:
$ qdbusxml2cpp -c MyServer -a myServer.h:myServer.cpp
com.inter.Demo.xml
The above command creates two adaptor class files “myServer.h” and “myServer.cpp”
with the class name “MyServer”.
The .h and .cpp files that just got generated in the current directory
will have the 2 methods and a signal that we defined in the interface file.
Next, we need to create a new project and make use of the created
adaptor class.
Create a new project name it as “ALU_DBUS”
(or whatever is convenient to you). To that project add a new C++ file and name
it “MyDemo” (or whatever is
convenient to you). Now, we need to make the signal and slots of “MyDemo.h” look the same as that of “myServer.h”. Before we do that we need
to copy the “myServer.h” and “myServer.cpp” to the current project.
After adding the files and copying the signals
and slot sections, the signal and slot section of “MyDemo.h” will look like this
public Q_SLOTS: // METHODS
void AddTwoNumbers(const QString &expr1, const QString &expr2);
void Display();
Q_SIGNALS: // SIGNALS
void MySignal(const QString &eventkind);
After adding the files and copying the signals
and slot sections, the signal and slot section of “MyDemo.h” will look like this
void
MyDemo::AddTwoNumbers(const QString &expr1, const QString &expr2)
{
//
handle method call com.inter.Demo.AddTwoNumbers
QMetaObject::invokeMethod(parent(), "AddTwoNumbers",
Q_ARG(QString, expr1), Q_ARG(QString, expr2));
qDebug()<<"Inside add two numbers";
qDebug()<< "Addition of two number is "<<
(expr1.toInt() + expr2.toInt());
}
void
MyDemo::Display()
{
//
handle method call com.inter.Demo.Display
QMetaObject::invokeMethod(parent(), "Display");
qDebug() << " I am in Display";
}
After implementing the slots in the MyDemo.cpp file we need to expose these services to the external clients. So, we need to create a Dbus connection. Before that create an instance of MyDemo and make it as a parent to the instance of the adaptor class ie., MyServer’s class
MyDemo *myServer = new MyDemo;
new
DemoMyServer(myServer);
The Dbus connection in
Qt can be created using the following statement:
QDBusConnection connection =
QDBusConnection::sessionBus();
What the above statement does is that it creates a seesionBus() to communicate between processes and returns an object
of that bus. To Know more about sessionBus
follow the link: ( http://qt-project.org/doc/qt-5/qdbusconnection.html#send
)
After the session bus is created we need to register our service (the
service that we are offering via the interfaces we wrote in the xml) In other
words, once we register our service we can let the clients access the methods
we offer via the dbus.
|
Registering a service
will define a contract on the bus but, we can only expose it through an object,that
can be done using the statement:
ret
= connection.registerObject("/",myServer);
Here the “/” is the object path and “myServer” is the Service offering
instance/object.
NOTE: In the .pro file add QT += dbus
Making use of the Service that we made
available
We need to create the client proxy class which can make use of the service which we are publishing. We can generate these two files from the “com.inter.Demo.xml” (the interface file that we created initially). The files can be created from the qbusxml2cpp tool, it can be done as follows:
|
After you execute this
command two files will be created. We need to instantiate these two files to
make use of the services. Create a new project, copy these two files in that
project. Create an instance of DemoMyClient,
register it with the dbus that has been created and use the services that are
exposed by the object.
It can be done using
the following statement:
DemoMyClient *client1 = new DemoMyClient("com.inter.Demo","/",QDBusConnection::sessionBus(),0);
The offered services
can be called just like local services
|
NOTE: In the .pro file add QT += dbus
(Note: the Dbus Server should already be running,
now run the Client project you should see that both the services that were
offered by another process were utilized by client process. Thus the IPC has
been achieved)
To summarize what we have done so far, we can put it in points below:
1.
Create an
interface file in xml
2.
Use the
xml2cpp tool to generate the adaptor class
3.
Use the
adaptor class in a new project and implement the services
4.
Create a
session bus(dbus) to make the communication possible b/w 2
process
5.
Register
the services (the contract defined by the interface) with the dbus connection
6.
Register
the Object so that services can be exposed through this object
7.
Create the
Client proxies so that the exposed services can be accessed
8.
Instantiate
the Client Proxy with the registered service on the bus with the appropriate
object
9.
Start
calling the methods of server using client object just like local methods
10. Dbus communication is achieved using Qt
More on QtDBus can be found
here (http://qt-project.org/doc/qt-5/qtdbus-index.html
)
Upesdifhau-ga Cesar Padilla https://wakelet.com/wake/4e5QRzzuSMirQbnQeaKei
ReplyDeletelimpgensoundking