Qt的信号/槽机制在网络上的应用

6
我希望能够通过网络发送Qt信号。使用Qt的元类型系统,序列化信号调用非常简单:
  • 使用静态方法::fromSignal创建一个qMetaMethod
  • 使用创建的元方法获取方法名称、参数名称、它们的typeIds [1]和值。
  • 将所有内容打包到您喜欢的格式(JSON、XML)中并发送它。
但是到目前为止,我还没弄清楚如何使用序列化数据来调用信号:QMetaObject :: invokeMethod(..)接受字符串形式的信号/方法名称。问题在于参数:它们必须作为QGenericArgument提供,并且只能通过使用需要实际类型(而不是它的名称字符串或typeId)和相关值的Q_ARG宏来创建这些对象。此外,参数数量必须在编译时定义,没有可以接受参数列表的invokeMethod(..)
我有什么遗漏吗?还是有更好/替代的方法来做到这一点?
[1] 更进一步的问题:如何确保使用Q_DECLARE_METATYPE(..)注册类型时始终获得相同的typeId?

在我看来,基于套接字的IPC是关键,而信号/槽的转换只是小菜一碟,这意味着信号和槽在IPC的不同进程之间都是已知的。 - Alexander V
@AlexanderVX 你能详细说明一下吗? - Nils
3
你是在重新发明QtRemoteObjects还是QtDBus? - peppe
1
你使用QtRemoteObjects,它抽象了传输。 - peppe
1
这是旧的内容,但可能仍然相关:https://bugreports.qt.io/browse/QTBUG-28833 - Silicomancer
显示剩余7条评论
2个回答

3

错误的观点是你不能自己创建一个QGenericArgument。虽然建议不要这样做,但你试图做的事情非常依赖于具体实现。其实并不难:你只需要提供类型名称和指向特定类型数据的指针即可。例如:

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

要查看更多示例代码,请参阅此回答中的可内省访问者部分。

如何确保使用Q_DECLARE_METATYPE(..)注册类型时,它们始终获得相同的typeId?

你无法保证它们始终获得相同的typeId。你应该使用类型名称,并且每个进程应在本地解析这些名称到typeId。

除非你想自己实现,否则请使用现成的解决方案,例如 MIT 许可的qt-remote-signals


目前为止,我已经成功地使其工作,而没有使用任何其他库。唯一不推荐的事情是直接使用QGenericArgument构造函数。 - Nils
1
相关:https://dev59.com/elzUa4cB1Zd3GeqPzxpZ - Nils

2
你真的应该考虑使用Qt远程对象,因为它们可以完成你需要的一切以及更多(心跳、自动重新连接断开连接、在幕后使用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));
};

然后,它需要使用内置的repc编译器(由qmake或cmake调用)将.rep文件转换为服务器端(称为“源”)和客户端(称为“副本”)的代码。每个由“源”调用的信号都会自动发送到每个连接的“副本”,而由“副本”调用的插槽则由“源”接收。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接