Механизм сигнала/слота Qt по сети

Я хочу иметь возможность отправлять сигналы Qt по сети. Сериализация вызова сигнала довольно проста с использованием системы метатипов Qt:

  • Создайте qMetaMethod с помощью статического метода ::fromSignal
  • Получите имя метода, имена параметров, их идентификаторы типов [1] и значения, используя созданный метаметод.
  • Упакуйте все в нужный формат (JSON, XML) и отправьте.

Но пока я не мог понять, как вызвать сигнал, используя сериализованные данные: QMetaObject::invokeMethod(..) принимает имя сигнала/метода в виде строки. Проблема заключается в аргументах: они должны быть представлены как QGenericArgument, и их можно создать только с помощью макроса Q_ARG, для которого требуется фактический тип (а не строка его имени или typeId) и соответствующее значение. Также количество аргументов должно быть определено во время компиляции, нет invokeMethod(..), который принимает список аргументов.

Я что-то упускаю? Или есть лучший/альтернативный способ сделать это?

[1] Дополнительный вопрос: как обеспечить, чтобы типы всегда получали один и тот же typeId при регистрации с использованием Q_DECLARE_METATYPE(..)?


person Nils    schedule 22.07.2016    source источник
comment
Вы ничего не упускаете.   -  person Sam Varshavchik    schedule 22.07.2016
comment
Э... Я не думаю, что механизм сигнала/слота вообще предназначен для работы в сети. Однако я был бы счастлив увидеть, что я ошибаюсь в этом отношении.   -  person Kyle Strand    schedule 22.07.2016
comment
ИМХО, IPC на основе сокетов - это ключ, а затем сигнал/слот преобразования - это просто арахис, означающий, что сигналы и слоты, известные как для обработки, так и для разных сторон IPC.   -  person Alexander V    schedule 22.07.2016
comment
@AlexanderVX, можете ли вы рассказать об этом подробнее?   -  person Nils    schedule 22.07.2016
comment
Вам нужен IPC через IP: doc.qt.io/qt-5/ipc.html   -  person Alexander V    schedule 22.07.2016
comment
Для этого вы можете использовать D-Bus, а в Qt есть классы для взаимодействия с D -Автобус.   -  person Jesper Juhl    schedule 22.07.2016
comment
Вы заново изобретаете QtRemoteObjects или QtDBus?   -  person peppe    schedule 22.07.2016
comment
Я не хочу ничего приглашать. Я видел D-Bus, но что, если вы используете другую шину/протокол?   -  person Nils    schedule 22.07.2016
comment
Вы используете QtRemoteObjects, который абстрагирует транспорт.   -  person peppe    schedule 22.07.2016
comment
Вы хотите предложить что-то вроде QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QHostAddress &host, quint16 port)?   -  person rgmt    schedule 22.07.2016


Ответы (2)


Неверно, что вы не можете создать QGenericArgument самостоятельно. Вам не рекомендуется этого делать, но то, что вы пытаетесь сделать, в любом случае очень зависит от реализации. В этом нет ничего сложного: вы предоставляете имя типа и указатель на данные данного типа. Например.:

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

Дополнительный пример кода см. в разделе Introspectable Visitor этого ответа.

Как обеспечить, чтобы типы всегда получали один и тот же typeId при регистрации с использованием Q_DECLARE_METATYPE(..)?

Вы не знаете. Вы должны использовать имена типов, и каждый процесс должен разрешать их локально.

Если вы не хотите реализовать это самостоятельно, используйте что-то готовое, например, лицензированный MIT qt- дистанционные сигналы.

person Kuba hasn't forgotten Monica    schedule 22.07.2016
comment
До сих пор это работало без каких-либо дополнительных библиотек. Единственное, что я не рекомендовал делать, это напрямую использовать ctor QGenericArgument. - person Nils; 25.07.2016
comment
Связанный: stackoverflow.com/questions /7721923/ - person Nils; 25.07.2016

Вам действительно следует рассмотреть возможность использования Qt Remote Object, поскольку они выполняют все, что вам нужно, и даже больше (пульс, автоматическое повторное подключение при отключении, работает либо с QLocalSocket, либо с QTcpSocket под капотом и т. д.). Проще всего получать сигналы по сети с минимальными затратами. усилие, о котором я знаю.

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

Вам просто нужно определить .rep текстовый файл, который подобен файлу определения IDL.

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

а затем этот файл .rep используется для генерации кода для серверной части (известного как «источник») и кода для клиентской стороны (известного как «реплика») с использованием встроенного компилятора repc, который вызывается qmake или cmake. Все сигналы, вызываемые «источником», автоматически отправляются через все подключенные «реплики», а слоты, вызываемые «репликами», принимаются «источником».

person mchiasson    schedule 30.05.2019