Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt's signal / slot mechanism over the network

Tags:

c++

qt

I want to be able to send Qt signals over the network. Serializing a signal call is quite straight forward using Qt's meta type system:

  • Create a qMetaMethod using the static method ::fromSignal
  • Get the method name, parameter names, their typeIds [1] and values using the created meta method.
  • Pack everything into your preferred format (JSON, XML) and send it.

But so far I could not figure out how to invoke a signal using serialized data: QMetaObject::invokeMethod(..) takes the signal / method name as string. The problem are the arguments: They must be provided as QGenericArgument and those can only be created by using the Q_ARG macro which requires the actual type (not a string of it's name or the typeId) and the concerning value. Also the number of arguments must be defined at compile time, there is is no invokeMethod(..) which takes a list of arguments.

Am I missing something? Or is there a better / alternative way to do this?

[1] Further question: How do I ensure that types always get the same typeId when they are registered using Q_DECLARE_METATYPE(..)?

like image 979
Nils Avatar asked Jul 22 '16 15:07

Nils


2 Answers

It is false that you can't create a QGenericArgument yourself. You're advised not to, but what you're trying to do is very implementation-dependent anyway. There isn't much to it: you provide a type name, and a pointer to the data of a given type. E.g.:

QGenericArgument one() {
  static const char type[] = "int";
  static const int data = "1";
  return QGenericArgument{type, (void*)&data);
}

See the Introspectable Visitor section of this answer for more example code.

How do I ensure that types always get the same typeId when they are registered using Q_DECLARE_METATYPE(..)?

You don't. You should be using type names, and each process should resolve these to typeids locally.

Unless you want to implement it yourself, use something ready made, like the MIT-licensed qt-remote-signals.

like image 81
Kuba hasn't forgotten Monica Avatar answered Oct 23 '22 03:10

Kuba hasn't forgotten Monica


You really should consider using Qt Remote Object since they accomplish everything that you need and more (heartbeat, automatic re-connection upon disconnect, works with either QLocalSocket or QTcpSocket under the hood, etc) It the easiest to get signals across the network with minimal effort that I know of.

https://doc.qt.io/qt-5/qtremoteobjects-index.html

You just need to define .rep text file, which is like an IDL definition file

class MyRemoteObject {
{
    SIGNAL(foo(int value));
    SIGNAL(bar(float value));
    SLOT(somethingChanged(int newValue));
};

and then it takes that .rep file to generate code for the server side (known as 'source') and code for the client side (known as 'replica') using a built-in repc compiler that is called by qmake or cmake. Every signals called by the 'source' is automatically sent across every connected 'replicas', and slots called by 'replicas' are received by the 'source'

like image 42
mchiasson Avatar answered Oct 23 '22 04:10

mchiasson