1

I'm trying to follow the External QIODevices examples, but it's missing to demonstrate how the srcNodes are being enabled and the replicas acquired.

I cant get the first example working, I tried:

.rep

class RemoteObject
{
    SLOT(void test(QString str))
    SIGNAL(signalTest(int x))
};

remoteobject.h

#include "rep_remoteobject_source.h"
class RemoteObject : public RemoteObjectSource
{
    Q_OBJECT
public:
public slots:
    void test(QString str) {
        qDebug() << "str:" << str;
    }
};
#include <QNetworkReply>
#include <QRemoteObjectHost>
#include <QTcpServer>
#include "remoteobject.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTcpServer tcpServer;
    tcpServer.listen(QHostAddress(QStringLiteral("tcp:://...")), 65213);

    QRemoteObjectHost srcNode;
    QObject::connect(&tcpServer, &QTcpServer::newConnection, &srcNode, [&] {
        srcNode.addHostSideConnection(tcpServer.nextPendingConnection());
    });

    RemoteObject remoteObject;
    bool ret = srcNode.enableRemoting(&remoteObject, "remoteObject");
    qDebug() << "enableRemoting:" << ret << srcNode.lastError();
    return a.exec();
}

srcNode.enableRemoting is returning false, lastError: QRemoteObjectNode::OperationNotValidOnClientNode.

In the enableRemoting documentation says: "Returns false if the current node is a client node"

And in the example there's a comment:

// Create the host node. We don't need a hostUrl unless we want to take

// advantage of external schemas (see next example).

Without a hostUrl set in the srcNode, it's probably being threatened as a client?

Am I not understanding it correctly or is something missing from the example?

-EDIT-

Using hostUrl as dylan mentioned:

server

    QTcpServer tcpServer;
    tcpServer.listen(QHostAddress(QStringLiteral("tcp://...")), 52074); // tcp as I'm not using a local ip

    QRemoteObjectHost srcNode;
    srcNode.setHostUrl(tcpServer.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);

    QObject::connect(&tcpServer, &QTcpServer::newConnection, &srcNode, [&]  {
        qDebug() << "new connection";
        srcNode.addHostSideConnection(tcpServer.nextPendingConnection());
    });

    RemoteObject remoteObject;
    if (!srcNode.enableRemoting(&remoteObject, "remoteObject")) {
        qDebug() << "failed:" << srcNode.lastError();
    }

client

    QRemoteObjectNode repNode;
    QTcpSocket *socket = new QTcpSocket(&repNode);
    QObject::connect(socket, &QTcpSocket::connected, &repNode,[&]()
    {
        qDebug() << "connected...";
        repNode.addClientSideConnection(socket); 
        QSharedPointer<RemoteObjectReplica> ptr;
        ptr.reset(repNode.acquire<RemoteObjectReplica>("remoteObject"));
 
        QObject::connect(ptr.data(), &RemoteObjectReplica::initialized, &a, [&]  {
            qDebug() << "initialized...";
            ptr.data()->test("hello world");
        });
    });
    
    socket->connectToHost(QHostAddress("..."), 52074);

connected is called but the RemoteObjectReplica is never initialized.

Cesar
  • 41
  • 2
  • 5
  • 16

1 Answers1

0

The QRemoteObjectHost needs to have an active connection before you can call enableRemoting(). The documentation says you don't need a valid host URL to call the method, but their 5.12 open source code indicates otherwise.

They have an example using a custom SSL server, which manually calls setHostUrl(), thus contradicting their documentation. This might be a helpful reference for the rest of your work.

I can get your first example to work if I simply call:

srcNode.setHostUrl(tcpServer.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);

The full code I have to make their example work is:

Server

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QTcpServer tcpServer;
    tcpServer.listen(QHostAddress(QStringLiteral("127.0.0.1")), 65213);

    // Create the host node.  We don't need a hostUrl unless we want to take
    // advantage of external schemas (see next example).
    QRemoteObjectHost srcNode;
    srcNode.setHostUrl(tcpServer.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);

    // Make sure any connections are handed to QtRO
    QObject::connect(&tcpServer, &QTcpServer::newConnection, &srcNode, [&srcNode, &tcpServer]() {
        srcNode.addHostSideConnection(tcpServer.nextPendingConnection());
    });

    Pong p;
    srcNode.enableRemoting(&p, "Test");

    return a.exec();
}

Client

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QRemoteObjectNode repNode;

    QTcpSocket *socket = new QTcpSocket(&repNode);

    QObject::connect(socket, &QTcpSocket::connected, &repNode, [socket, &repNode]() {
        repNode.addClientSideConnection(socket);
    });

    QScopedPointer<PongReplica> p(repNode.acquire<PongReplica>("Test"));

    socket->connectToHost(QHostAddress(QStringLiteral("127.0.0.1")), 65213);
    socket->waitForConnected(3000);  // Wait a max of 3 seconds for connection to open.

    p->waitForSource();  // This is the most important part.
    // Your replica cannot send data to the server until it is fully
    // initialized. You can, however, use any default values on properties.

    return a.exec();
}

Pong and PongReplica are just simple objects I made with the repc generator which just have a boolean member variable.

class Pong
{
    PROP(bool flag = false)
}
dylan
  • 68
  • 7
  • Hi dylan, how are you acquiring the replica on the client side? I got the `"connected..."` message but `qt.remoteobjects: connectionToSource is null` in the line `ptr.data()->test("hello world");` https://pastebin.com/uJZ7YkDZ – Cesar May 04 '23 at 00:33
  • In the example link you sent, on the [client](https://code.qt.io/cgit/qt/qtremoteobjects.git/tree/examples/remoteobjects/ssl/sslcppclient/main.cpp?h=6.5) side it's using a `QScopedPointer` I also tried it but still got the same error. I noted that when the host reopens the client doesn't auto-reconnect, do i need to detect it and call `connectToHost` again? – Cesar May 04 '23 at 01:15
  • Hi Joey, if you're using the client code from your example #2 with the server code from example #1, you will need to change the host address you connect to. Remove the schema from the URL and try just using `"127.0.0.1:65212"` instead of `"tcp://127.0.0.1:65212"`. I would recommend using the code that matches the first example from the external QIODevices page for your client, since we're not really using external schemas. Once they call `connectToHost`, wait for the connection to be established, then try to acquire your replicas. – dylan May 04 '23 at 16:57
  • I should clarify, don't give your `QRemoteObjectNode` on the client a URL to connect to. If you give the node a URL, it will attempt to internally manage connections and probably fail. When you call `addClientSideConnection()` it will link the node to your server properly. The key is to not try to acquire a replica until that function is done. Also, they only use `QScopedPointer` to manage the lifetime of the replicas, so that they are deleted when the `tester` class is deleted. – dylan May 04 '23 at 17:06
  • `"I would recommend using the code that matches the first example"` I'm already, removing the `AllowExternalRegistration` schema, the server fails (first example), `"don't give your QRemoteObjectNode on the client a URL to connect to"` how it will call the `addClientSideConnect()` without calling connecToHost() before? I'm confused – Cesar May 04 '23 at 17:57
  • I edited the question, focusing it on the first example, I added how I'm setting the server and client with your suggestions. – Cesar May 04 '23 at 18:25
  • Apologies, I should have included the full code I was using to start with. I've edited my answer to include the code I used to test. – dylan May 04 '23 at 20:30
  • I wonder if it's a bug, even setting a `heartbeat` on the client it doesn't reconnect anymore when the server is restarted. Does it auto-reconnect at your side? https://bugreports.qt.io/browse/QTBUG-97688 – Cesar May 05 '23 at 16:11
  • Is there a reason you need to use external IO devices? Because if you use the internal version, it will handle all of this for you. Your question about reconnecting would be better solved by existing answers on StackOverflow, or by opening a new question. https://stackoverflow.com/questions/11600288/qtcpsocket-client-auto-reconnect Try resetting the socket and then after a delay (so not inside the error/disconnected handler) reconnect. – dylan May 05 '23 at 16:12
  • What internal version? Im using RO with a socket – Cesar May 05 '23 at 16:19
  • Internal as in just passing the URLs to your QRemoteObjectHost and QRemoteObjectNode. Or even using local servers, like `QRemoteObjectHost src(QStringLiteral("local:source"));` and `QRemoteObjectNode repNode(QStringLiteral("local:source"));` Qt will then manage incoming and outgoing connections for you, no need to create and pass sockets around. – dylan May 05 '23 at 16:34
  • But this will work locally only, don't? I'm using it to share data between networks – Cesar May 05 '23 at 16:36
  • You can pass actual URLs to expose them externally, too. `QRemoteObjectHost srcNode(QStringLiteral("tcp://127.0.0.1:65213"));` and `QRemoteObjectNode repNode(QStringLiteral("tcp://127.0.0.1:65213"));` Substitute the addresses and ports for what you need. – dylan May 05 '23 at 16:47
  • Then what's the point of the socket? – Cesar May 05 '23 at 16:49
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253496/discussion-between-dylan-and-joey). – dylan May 05 '23 at 16:52