D-Bus-Programmierung

Alles rund um die Programmierung mit Qt
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

D-Bus-Programmierung

Beitrag von LonelyPixel »

Hallo,

seit langer Zeit hab ich wieder was mit Qt zu tun. Diesmal geht es u.a. darum, D-Bus-Funktionen in eine bestehende Anwendung einzubauen. Doch leider stellt sich die Dokumentation im Web zu dem Thema als überaus bescheiden heraus. Funktionierende Beispiele habe ich überhaupt nicht gefunden, trotz dutzender Suchbegriffe diverser Klassennamen etc.

Also ich kann bislang einen Service registrieren und ein Objekt darauf veröffentlichen. Wenn ich im 2. Prozess eine Method-Call-Nachricht absende, kommt sie auch an und die Methode des veröffentlichten Objekts wird ausgeführt. Wenn ich nun aber den Weg zuende gehen möchte, um das Objekt nahtlos in der Client-Anwendung zu verwenden, haut gar nichts mehr hin. Zuletzt gab es Linker-Fehler.

Hier mein Code:

IpcServer.h

Code: Alles auswählen

#ifndef IPCSERVER_H
#define IPCSERVER_H

#include <QObject>

class IpcServer : public QObject
{
    Q_OBJECT
public:
    explicit IpcServer(QObject *parent = 0);
	void pressButton();

signals:

public slots:
	void TestSlot();
};

#endif // IPCSERVER_H
IpcServer.cpp

Code: Alles auswählen

#include <Utils/Logger.h>
#include "IpcServer.h"

IpcServer::IpcServer(QObject *parent) :
    QObject(parent)
{
}

void IpcServer::pressButton()
{
	LOG_Debug("IPC: pressButton");
}

void IpcServer::TestSlot()
{
	LOG_Debug("IPC TEST SLOT");
}
ServerMain.cpp (Ausschnitt)

Code: Alles auswählen

	QDBusConnection bus = QDBusConnection::systemBus();
	IpcServer svr;
	bus.interface()->registerService("xy.Terminal");
	bus.registerObject("/terminal", (QObject *) &svr, QDBusConnection::ExportAllContents);
ClientMain.cpp

Code: Alles auswählen

#include <QDebug>
#include <QtDBus>

#include "ServerMain/IpcServer.h"

int main()
{
	QDBusConnection bus = QDBusConnection::systemBus();

	/*
	QDBusMessage msg = QDBusMessage::createMethodCall("xy.Terminal", "/terminal", "", "TestSlot");
	QDBusMessage reply = bus.call(msg);
	qDebug() << reply;
	*/

	QObject *obj = bus.objectRegisteredAt("/terminal");
	IpcServer *svr;
	if (obj && (svr = qobject_cast<IpcServer*>(obj)))   // Diese Zeile hab ich irgendwo in nem KDE-Programm gefunden, mit Google Code Search
	{
		svr->pressButton();
	}
	return 0;
}
ServerMain lässt sich erstellen, aber bei ClientMain gibt's folgende Fehler:

undefined reference to 'IpcServer::staticMetaObject'
undefined reference to 'IpcServer::pressButton'

Ist ja klar, weil der Code vom IpcServer ja nicht im Client liegt, sondern nur im Server. Nun hab ich irgendwas von nem QDBusAbstractInterface gelesen, aber wie man damit umzugehen hat, kann mir niemand erklären, auch nicht die Qt-Dokumentation.

Hat hier schonmal jemand D-Bus in Qt verwendet und kann mir verraten, wie das geht? Vielleicht könnte mir sogar jemand ein Beispiel machen, damit ich es auch mal verstehe?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Beispiele werden doch ausreichend mitgeliefert:

Code: Alles auswählen

$ ls src/qt4/4.6.3/examples/dbus/
complexpingpong  dbus-chat  dbus.pro  listnames  pingpong  remotecontrolledcar
Oder reichen die dir nicht?
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

Huch, also unter /usr/share/doc/packages/libqt4/examples/qdbus/ hätte ich jetzt sicher nicht das Suchen angefangen... Aber gibt's zu den Beispielen denn auch eine Erklärung? Die verwenden im Code Dinge, von denen ich nach lesen aller möglichen Referenzseiten zu QtDBus noch gar nichts gehört hab. Z.B. XML-Dateien. Andere Dateien scheinen automatisch generiert zu sein, womit und wofür kann ich nicht erkennen.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

schau mal ob du qtdemo mitinstalliert hast ... wenn ja, hast du darüber Zugriff auf alle Examples und nen direktlink in die Doku des Examples ... wobei die "nur" zu ~75% gut (für noch-nie-mit-klasse-gearbeitet-hab-Leute) dokumentiert sind
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

Du meine Güte, das qtdemo legt ja den ganzen Rechner lahm! Was tut dieses Programm denn alles? Von D-Bus war da aber nichts zu sehen. Hat noch jemand Vorschläge?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Suche nach "dbus xml" liefert z.B. das:
http://dbus.freedesktop.org/doc/dbus-tu ... rospection
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

Das freedesktop-Tutorial hab ich schon durch. Leider wird dort kein bisschen Qt beschrieben, nur GLib (was immer das ist, aber es schaut nicht so aus, als könnte ich es brauchen). Und ich gehe davon aus, dass das Veröffentlichen von Objekten Qt-spezifisch ist.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Hier anfangen und die Links durchhangeln.
Was DBus ist und alles mögliche sonst noch, steht dann auf der Hauptseite. Warst du da auch schon?
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

Ja, die Qt-Referenz zu D-Bus hab ich durch und bei freedesktop steht ja nichts zu Qt (außer Links zur genannten Qt-Referenz). Die Qt-Referenz ist aber gewohnt knapp und enthält keine relevanten Beispiele, wie man's wirklich verwendet. So wie es da steht funktioniert es anscheinend nicht. Aber mal schauen, vielleicht treibt sich hier ja noch jemand rum, der QtDBus selbst schonmal verwendet hat und mir das erklären kann. Derweil versuch ich mal, aus dem Beispiel mit dem ferngesteuerten Auto schlau zu werden.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

LonelyPixel hat geschrieben:So wie es da steht funktioniert es anscheinend nicht.
Was heißt "funktioniert nicht"? Dein dbus-daemon rennt aber schon?
Aber mal schauen, vielleicht treibt sich hier ja noch jemand rum, der QtDBus selbst schonmal verwendet hat und mir das erklären kann.
Ich hab es schon verwendet, und mehr als die Doku hab ich nicht gebraucht. Prinzipiell ist es das Gleiche mit HTTP und FTP-Verbindungen. Es gibt eine Spezifikation, wie Verbindungen aufgebaut werden, wie Daten verschickt werden, Header usw. Wie das ganze dem Programmierer präsentiert wird ist vom Framework abhängig. boost::asio, QNetworkAccessManager, QHttp, die GLib-Methoden, rohe Sockets usw.

Worin liegt denn dein Problem? Was genau willst du erreichen? Kannst du ein minimales, kompilierbares Beispiel erstellen und anhängen, sodass wir uns ein Bild machen können?

Zu deinem ersten Post:
Die undefined reference bekommst du weg, wenn du alles, was in Server und Client gemeinsam gebraucht wird, in eine Lib verfrachtest und diese zu beiden Exen linkst.
Und wenn du schon "ein KDE-Programm" zitierst, wäre es nicht schlecht zu sagen welches, am besten samt Angabe welche Datei + Codezeile.
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

Also, "funktioniert nicht" heißt, dass ich es nicht am Compiler vorbei geschafft habe. Compiliert nicht.

Es funktioniert dann, wenn ich kein veröffentlichtes Objekt abrufen und verwenden will (Proxy-Objekt), sondern eben einfach eine method-call-Nachricht über D-Bus absende (auskommentierter Code in ClientMain.cpp). Die wird auf dem Server korrekt aufgerufen. Der D-Bus-Dienst läuft also. Nur das mit dem Objekt abrufen haut nicht hin.

Die Stelle im KDE-Programm finde ich jetzt nicht mehr. Ich hab einfach in Google Code Search rumgewühlt. Heute ist das Ergebnis für "objectRegisteredAt" nicht mehr dabei.

Ein minimales compilierbares Beispiel kann ich nicht angeben. Das Beispiel aus dem ersten Beitrag ist recht minimal, compiliert aber nicht.

Ich möchte mit dem gringstmöglichen Aufwand ein QObject veröffentlichen und an anderer Stelle verwenden. Dass ich den Header des Objekts dafür brauche, ist mir klar. Aber den Code möchte ich dafür nicht brauchen. Erstens ist der in meinem Fall riesengroß und zweitens wird der sowieso nicht verwendet, weil die Aufrufe ja an den Server übertragen und dort ausgeführt werden. Den Code nicht einzubinden stellt also sicher, dass er ihn auch wirklich nicht verwendet (lokal aufruft), was er ja auch nicht soll. So lange es ohne den eingebundenen Server-Code nicht läuft, ist also irgendwas anderes falsch.

In der Qt-Referenz steht was von einem Adapter, den man sich für jedes zu veröffentlichende Objekt anlegen kann. Irgendwo in der Nähe steht aber auch, dass man den nur braucht, wenn man das Exportverhalten anpassen will. (So hab ich die knappe Beschreibung jedenfalls verstanden.) Will ich aber nicht, das Objekt wird nur für IPC erstellt und soll genauso exportiert werden, wie es ist. Aber das geht ja irgendwie nicht.

Was fehlt mir jetzt?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

LonelyPixel hat geschrieben:Du meine Güte, das qtdemo legt ja den ganzen Rechner lahm!
Das liegt dann wohl am Rechner :D Es ist eine QtApp die alle Beispiele nach Rubriken gegliedert auflistet, man kann die Rubrik anklicken und bekommt dann ein (Stand-) Bild von der entsprechenden App sowie etwas erklärenden Text ... ausserdem 2 Knöpfe - eines startet den QtAssistent und springt zum entsprechenden Beispiel, das andere launch'ed das hoffentlich kompilierte Example.
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

Im Haupt- und im ersten Untermenü ist die CPU permanent zu 100% beschäftigt. Der PC ist nicht sonderlich schnell, aber zum Code bearbeiten und Compilieren unter Linux reicht's. Der war halt grade noch übrig. Und weil er in nem kleinen Loch steht, hab ich nur ne VNC-Verbindung dorthin, die mir beim ersten Start von qtdemo bald abgerissen wäre... Die beiden Buttons funktionieren übrigens nicht. Das Beispiel kann er nicht starten (ohne Angabe von Gründen) und die Dokumentation erscheint einfach nie. Vielleicht liegt's am OpenSuse 10.3 mit dem Standard-Qt 4.3 dadrauf (Projektanforderung...).
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

LonelyPixel hat geschrieben:Es funktioniert dann, wenn ich kein veröffentlichtes Objekt abrufen und verwenden will (Proxy-Objekt), sondern eben einfach eine method-call-Nachricht über D-Bus absende (auskommentierter Code in ClientMain.cpp). Die wird auf dem Server korrekt aufgerufen. Der D-Bus-Dienst läuft also. Nur das mit dem Objekt abrufen haut nicht hin.
[...]
Dass ich den Header des Objekts dafür brauche, ist mir klar. Aber den Code möchte ich dafür nicht brauchen.
Da fehlts aber an C++-Grundlagen. Der Linker braucht bei jedem getatigten Methodenaufruf die Definition der Methode, egal wo oder wie der Aufruf stattfinden soll. Du kannst mit Qt "zaubern", indem du alle Methoden, die aufgerufen werden sollen, als SLOT exportierst und den qobject_cast bleiben lässt und Methodenaufrufe auf dem blanken QObject via QMetaObject::invokeMethod machst.
Trotzdem: was passt dir an dem simplen Aufrufen via dbus nicht? Brauchst du denn wirklich das Server-Objekt?
LonelyPixel
Beiträge: 23
Registriert: 5. Juli 2008 23:21

Beitrag von LonelyPixel »

franzf hat geschrieben:Der Linker braucht bei jedem getatigten Methodenaufruf die Definition der Methode, egal wo oder wie der Aufruf stattfinden soll.
Das wollte ich eben vermeiden. Irgendwie muss das doch zu schaffen sein. Dass der Code so nicht geht, ist klar. Stattdessen muss man halt irgend einen anderen Typ verwenden, auf dem man die Methoden aufrufen kann, nur nicht den hier, weil der ja nicht implementiert ist. Ich kenne RPC nur so, dass irgendeine Instanz zur Laufzeit dann ein Proxy-Objekt generiert, das die gleichen Methoden anbietet, wie das originale, aber die Aufrufe dann durch den Kommunikationskanal umleitet. Wie das mit Qt geht, weiß ich nicht.
Du kannst mit Qt "zaubern", indem du alle Methoden, die aufgerufen werden sollen, als SLOT exportierst und den qobject_cast bleiben lässt und Methodenaufrufe auf dem blanken QObject via QMetaObject::invokeMethod machst.
Na das hat (neben erhöhtem Aufwand) ja wieder in etwa den Charme von rohen Nachrichten, die man sich zusammenbasteln muss. Dann kann ich es auch bleiben lassen.
Trotzdem: was passt dir an dem simplen Aufrufen via dbus nicht? Brauchst du denn wirklich das Server-Objekt?
Naja, Objektorientierung? Brauchen tu ich gar nix, aber wenn Qt die Nutzung von D-Bus schon vermeintlich ohne Stilbruch ermöglicht, wäre es doch auch schön, wenn man das nutzen könnte. Naja, anscheinend geht es aber doch nicht. Qt verliert seinen Zauber... C++ mag ich nicht. Nach zuerst einigen Jahren *Basic und *Pascal, danach einigem *C++ bin ich nun seit langem glücklich mit C#. Damit verglichen ist (die Sprache) C++ nur noch umständlich. Aber leider gibt's das Programm jetzt nunmal und ich muss es irgendwie mit IPC zum Laufen bringen.

Das ferngesteuerte Auto verwendet einige generierte Code-Dateien, sieht also nach offline erzeugtem Proxy-Code aus. Mal eben zur Laufzeit passiert da gar nichts. Dann kann ich das mit den Objekten auch bleiben lassen und auf die Ebene der einzelnen Nachrichten runtersteigen. So praktische Dinge wie Signal-Slot-Verbindungen werden damit aber nicht mehr funktionieren, oder? Plain C...
Antworten