summaryrefslogtreecommitdiffstats
path: root/src/remoteobjects/doc/src/remoteobjects-index.qdoc
blob: 74cd98b1290192899746bf1274909880352a20de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/****************************************************************************
**
** Copyright (C) 2014 Ford Motor Company
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtRemoteObjects module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
\page qtremoteobjects-index.html
\title Qt Remote Objects
\brief An introduction to Inter-Process Communication using Qt Remote Objects

\target Qt Remote Objects
\section1 Remote Object Concepts

Qt Remote Objects (QtRO) is an inter-process communication (IPC) module
developed for Qt. The idea is to extend existing Qt's functionalities to enable
an easy exchange of information between processes or computers.

One of the key features of Qt to enable this is the distinction between an
objects API (defined by its Q_Property, Signals and Slots) and the
implementation of that API. The purpose of QtRO is to meet the expected API, even
if the true QObject is in a different process. A Slot called on a copy of an
object (called a \l {Replica} in QtRO) is forwarded to the true object (called
a \l {Source} in QtRO) for handling. Updates to the \l {Source} (either
property changes or emitted Signals) are forwarded to every \l {Replica}.

A \l {Replica} is a light-weight proxy for the \l {Source} object, but one that
supports the same connections and behavior of QObjects, which makes them as
easy to use as any other QObject provided by Qt. Everything needed for the \l
{Replica} to look like the \l {Source} object is handled behind the scenes by
QtRO.

Note that Remote Objects behave differently from traditional remote procedure
call (RPC) implementations. In RPC, the client makes a request and waits for
the response. In RPC, the server does not push anything to the client unless it
is in response to a request. The design of RPC is often such that different
clients are independent of each other (for instance, two clients can ask a
mapping service for directions and get different results). While it is possible
to implement this in QtRO (as \l {Source} without properties, and Slots that
have return values), it is designed more to hide the fact that the processing
is really remote. You let a node give you the \l {Replica} instead of creating
it yourself, possibly use the status signals (\l {QRemoteObjectReplica::} {isReplicaValid()}),
but then interact with the object like you would with any other QObject-based type.

\section1 Uses

Consider a sensor, a global positioning system (GPS) receiver for instance. In
QtRO terms, the \l {Source} would be the process that directly interacts with
the GPS hardware and derives your current location. The location would be
exposed as QObject properties, and the periodic updates to the location would
update the properties and emit property changed signals. \l {Replica}s would be
created in other processes and would always know your current location, but
would not need any of the logic to compute the location from the sensor data.
Connecting to the location changed Signal on the \l {Replica} would work as
expected, as the signal emitted from the \l {Source} would trigger the Signal
emission on every \l {Replica}.

Another example of QtRO usage would be for a service (for example, access to a printer).
The \l {Source} is again the process controlling the printer directly. Here you
would again likely have properties monitoring the ink levels or whether the printer is
currently busy. However, the key feature, being able to print something, needs to be
passed back to the printer. This aligns with the Qt Slot mechanism, which QtRO
uses as the way for \l {Replica}s to make calls on the \l {Source}. In effect,
properties and signals go from \l {Source} to \l {Replica}s, while slots go
from (a) \l {Replica} to the \l {Source}. Assuming a print request is accepted,
the printer status would change, which would change the status property. This
would then be reported to all \l {Replica}s.

\section1 Nodes

QtRO needs a helper class to make this work: the QRemoteObjectNode.
QRemoteObjectNodes (let's shorten the name to Node for now) are what enables
the passing of information between processes. All of the QtRO functionality is
enabled by a small number of distinct packets passing the necessary data
between nodes.

Each process that participates in QtRO's IPC will instantiate a Node-based type
(QRemoteObjectNode, QRemoteObjectHost, or QRemoteObjectRegistryHost). The
latter types of Nodes provide additional functionality. Both QRemoteObjectHost
and QRemoteObjectRegistryHost support the \l {QRemoteObjectHostBase::}{enableRemoting()}
(and the corresponding \l {QRemoteObjectHostBase::}{disableRemoting()}) methods,
which are the key methods to expose \l Source objects to the network. In order
to use the \l Registry functionality, there should be one QRemoteObjectRegistryHost
on the network.
All other nodes can then pass the RegistryHost's URL to the Node's \e registryAddress
constructor parameter, or pass the URL to the \l {QRemoteObjectNode::}{setRegistryUrl()}
method.

QtRO works as a peer-to-peer network. That is, in order to \l
{QRemoteObjectNode::acquire()}{acquire()} a valid \l {Replica}, the \l
{Replica} node needs a connection to the node that hosts its \l {Source}. A
host node is a node that allows other nodes to connect to it, which is
accomplished by giving hosts unique addresses (the address is provided to the
QRemoteObjectHost constructor or set by the setHostUrl method). The node that a
\l {Replica} is requested from must establish the connection to the host node
in order to initialize the \l {Replica} and keep it up to date.

\section1 Connecting Nodes using QtRO URLs

Host Nodes use custom URLs to simplify connections. While the list will likely
be extended, QtRO currently supports two types of connections. A "tcp"
connection (using the standard tcp/ip protocol) supports connections between
devices as well as between processes on the same device. The 2nd option is a
"local" connection - which can have less overhead, depending on the underlying
OS features - but does not support connectivity between devices.

When using a local connection, a unique name must be used. For tcp connections,
a unique address and port number combination much be used.

There is currently no \l {http://www.zeroconf.org/} {zeroconf} facility
included in QtRO. All processes or devices must therefore know beforehand how to
connect to each other. A \l {QRemoteObjectRegistry} (see below) can be used to
simplify the connection process for a network with multiple Host Nodes.

Connection types are summarized in the following table.
    \table 90%
    \header \li URL  \li Host Node           \li Connecting Node
    \row    \li \l {QUrl}("local:replica")   \li \l {QLocalServer}("replica") \li \l {QLocalSocket}("replica")
    \row    \li \l {QUrl}("tcp://192.168.1.1:9999")   \li \l {QTcpServer}("192.168.1.1",9999) \li \l {QTcpSocket}("192.168.1.1",9999)
    \endtable

Nodes have a couple of \l {QRemoteObjectHostBase::enableRemoting()}
{enableRemoting()} methods that are used to share objects on the network (this
will produce an error if the Node is not a Host Node however). Other
processes/devices that want to interact with a shared object use one of the \l
{QRemoteObjectNode::acquire()} {node's acquire()} methods to instantiate a
replica.

\target Source
\section1 Source objects

A Remote Object Source is the QObject that is responsible for the
implementation of the exposed API.

At a high level, you have a choice of using a QObject type directly as a source
or defining the desired API in a .rep template for use with the \l {repc}
compiler.

If you already have a fully defined QObject, it can become a Source simply by
passing it to \l {QRemoteObjectHostBase::enableRemoting()}. This lets other
processes/devices create a \l {Replica} of the object to interact with (see \l
{Remote Object Interaction}). You can then instantiate \l {QRemoteObjectDynamicReplica}s
of your object, or use the \l {QOBJECT_REPLICA} macro in your project file,
which will use \l {repc} to create a header file describing the Replica for
use in that process/on that device (and provides compile-time checks).

Letting \l {repc} generate a \l {Source} header file for your project (using
the \l {REPC_SOURCE} macro) provides three options of implementing the desired
API. If your class name was Foo, the options would be the following (and see \l
{The rep file format} for help in creating a rep file)

\list
\li \l {TypeSimpleSource} {FooSimpleSource} inheritance
\li \l {TypeSource} {FooSource} inheritance
\li \l {TypeAPI} {FooSourceAPI} usage with your own QObject
\endlist

\target TypeSimpleSource
There is a <Type>SimpleSource class defined in the header, which provides
basic getter/setter methods for each property and implements data members of
the correct property type in the header. Here "<Type>" represents the class
name from the .rep file, so if your class is of type "MyType" in the .rep file,
there will be a MyTypeSimpleSource class declared in the produced header file.
This is a fast way to get started using the API. To use this class, you need to
inherit from this class and implement any defined slots (which are pure virtual
in the generated header file). Whatever logic is needed to manage the
exposed properties and define when Signals need to be emitted would be added to
the overriding class as well.

\target TypeSource
If you need to hide the implementation details, you can use the <Type>Source
class instead, which is the 2nd class declared in the same resulting header
file. This class definition does not provide data members, and makes the
getter/setter functions pure virtual as well. You have more flexibility in how
you implement the class, although you need to write more code. This defines the
API for both the source and replica side from a single .rep template file.

\target TypeAPI
Finally, there is the <Type>SourceAPI class generated in the header. This is a
templated class, for use specifically by the templated version of \l
{QRemoteObjectHostBase::enableRemoting()} function overload, which allows you to
use any QObject that supports the desired API as the source. You will get
compile-time warnings if the class does not provide the correct API, and using
this class allows you to hide or convert properties or signal/slot parameters.

\note The QObject API is \b never exposed. For instance, while a \l
{Replica} will have a destroyed signal, the destroyed signal of the source is
not propagated. The \l {Source} and each \l {Replica} are unique QObjects with
their own connections. The API that is exposed is defined by the .rep template
used by \l {repc}, or in the case of raw QObjects, all API elements defined in
the inheritance chain from a specific ancestor. Unless you define
Q_CLASSINFO("RemoteObject Type") in an ancestor, the QObject's parent is used.
If Q_CLASSINFO("RemoteObject Type") is used, that class's API is the lowest
level of API used.

\section1 Identifying Sources

Since more than one \l {Source} can be shared by a host node, each \l
{Source} requires a name. All \l {repc} generated headers include a way for the
node to determine the class name (Q_CLASSINFO for replica/simplesource/source
types, or a static name() function for the SourceAPI type). If you pass your
own QObject type to \l {QRemoteObjectHostBase::enableRemoting()}, the name will
be determined using the following logic:
\list
    \li If the object or any of its ancestors has Q_CLASSINFO of type
        "RemoteObject Type" defined, the provided name will be used.
    \li Otherwise, the QObject's objectName (if set) will be
        used. \li If neither is available, the call to
        \l {QRemoteObjectHostBase::enableRemoting()} will fail, returning False.
\endlist

\target Replica
\section1 Replica objects

A remote object replica is a proxy object that has (approximately) the same API
as the \l {Source} QObject it is replicating. There are a few additional
properties and signals to make it possible to detect when the Replica is
initialized or if it loses the connectivity to the \l {Source} object. There
are a few other differences: a constant property on the source cannot
be constant on the replica. The value will not be known at the time the
replica is instantiated, it will only be known once the replica is initialized
(see \l {Remote Object Interaction}).

A compiled replica is a \l {QRemoteObjectReplica} based type, where the derived
class definition is automatically generated by the \l {repc} compiler. Only a
header file is generated (and using the REPC_REPLICA macro in your .pro file
can make generation part of the build process), but it is a complete type.
There is no public constructor, you need to use the \l
{QRemoteObjectNode::acquire} template function to create the Replica instance.

A \l {QRemoteObjectDynamicReplica} can be generated at runtime. To do so, you
call the non-templated version of \l {QRemoteObjectNode::acquire()}, passing in
as an argument the \l {Source} name (a QString). Dynamic replicas are a bit
more verbose to use from C++, but do not require compilation and can be
used easily in QML or (potentially) exposed to scripting languages such as Python.
Dynamic replicas do not support initial property values, and do not support
introspection until they have been initialized.

An important difference between these two ways of creating replicas is the
behavior before the replica is initialized. Since a Dynamic replica only gets
a metaObject after initialization, it basically has no API before
initialization. No properties, and no Signals to connect slots to.
Due to the compile-time creation of the metaObject for compiled replicas,
their API is available when the replica is instantiated. You can even provide
default values for Properties in the template file, which will be used until
the replica is initialized with current values from the Source.

See \l {QRemoteObjectReplica} and \l {QRemoteObjectDynamicReplica}

\section1 Replica Initialization

A host node will share the list of sources it hosts and every other node that
connects to it. It will send updates when sources are added or removed from the
list. In this way, a connected node will always know what sources it can attach
to. Changes to a specific \l {Source} are only propagated to nodes that have a replica of
that source. This avoids unnecessary network traffic.

When a node acquires a replica for a known source, the replica node sends a
request for that source to the host node. Upon receipt of this request, the
host will create a reply packet with the current values of all properties of
the source. If the requested replica is dynamic, it will include the API
definition for the source. The replica node will be included in the list of
connections that receive changes to that source from then on.

If a replica is instantiated but the node is not connected to the node that
hosts the requested source (or that object lives in a host node process, but
sharing/remoting has not been enabled for the QObject), the Replica will still
be created, it will just remain uninitialized.

If, at a later time, the replica node gets notified that the requested source is
available from a connected node, it will at that point request the source and
start the initialization process.

If the connection to a host node is lost, the replica will transition to the
invalid state. It will attempt to reconnect and will re-initialize if the
connection is restored (this making sure all Properties are current).

\target Registry
\section1 The Registry

When you \l {QRemoteObjectNode::acquire()} a replica, the node URL is not passed
as an argument. This means you do not need to specify the host node, but it does
require you to have some other means of connecting to that host. Without the
registry, it is necessary to manually call \l {QRemoteObjectNode::connect()},
from each node, to every host node that has \l {Source} objects it should
replicate. This is fine for small or static networks, but does not scale.

The registry provides a simpler way to establish these connections. Every node
that wants to be part of the registry's network connects to the registry. The
registry is itself a specialized source object, and thus is hosted by a node.
Connecting to the registry is simply a matter of passing the registry's URL to
the QRemoteObjectNode or QRemoteObjectHost constructor, or passing the URL to
the setRegistryUrl method.

The registry is tightly integrated with QtRO. Whenever a \l {Source} is added
or removed, the name/URL is updated in the registry automatically. So once
your node is connected to the registry, it is not necessary to connect to any
other nodes manually. If you request an object on the network and you aren't
connected to the hosting node, the registry will know what URL to connect to
and will initiate the connection. Once connected (and the list of available
objects is passed along, including the desired \l {Source}), the initialization
process for the requested \l Replica will start automatically.

\section1 Remote Object Interaction

Source/replica interaction is directional. Property changes and signal emission
happen on the source, and are propagated to all replicas. If a property is
writable, you can call the setter function on a replica. This will be forwarded
to the source, and if a change is made, it will be made on the source and
subsequently forwarded to all replicas. To the replica, it is then an
asynchronous call, with latency before the change takes effect.

Whereas you can emit a signal on a replica, this may have unexpected results and
is discouraged for that reason. It will only trigger slots connected to the
replica itself, no slots connected to the source or other replicas. Like
property setters, slot invocations on a replica are forwarded to the Source to
run.

The behavior above is implemented automatically by QtRO, there is no need to
write any replica implementation code. It will be handled automatically at
runtime for dynamic replicas, or at compile time for repc generated headers.

\section1 Replica Ownership

The acquire methods return a pointer to the replica QObject instantiated by the
node. The node has no way of knowing the intended lifetime of the replica, so
it is the responsibility of the calling program to delete the replica when it
is no longer needed.

You can instantiate multiple copies of the same replica (this may be necessary
in QML for instance). All replicas of the same source from a single node will
share a private data member which handles the network communication. This means
multiple instances of a \l {Replica} do not introduce additional network
traffic, although there will be some additional processing overhead. Failing to
delete replicas will prevent the reference count on this private object to be
invalid, and cause unnecessary network communication until the calling process
exits. For this reason, it is recommended that \l {QScopedPointer} or \l
{QSharedPointer} be used to help track a replica lifetime.

\section1 Remote Object Public Classes

The following classes make up the public interface for Qt Remote Objects:

\generatelist{classesbymodule QtRemoteObjects}

\omit
\section1 Troubleshooting

TODO
\endomit
*/