[gelöst] Synchroner QNetworkAccessManager

Alles rund um die Programmierung mit Qt
Antworten
heikob
Beiträge: 81
Registriert: 23. März 2005 23:20

[gelöst] Synchroner QNetworkAccessManager

Beitrag von heikob »

Hallo,

ich versuche gerade eine Schnittstelle zu CouchDB zu implementieren. Prinzipiell funktioniert das auch ganz gut. Allerdings basiert das Ganze auf asynchronen HTTP-Requests, das heißt, ich würde aus meinem Programm eine Anfrage verschicken und müsste die Antwort mit einem Signal abfangen. Wie das in der Anwendung aussehen würde, wage ich mir gar nicht auszumalen. Daher hätte ich zumindest einige Anfragen gerne synchron.

So mache ich es bisher:

Code: Alles auswählen

void QtCouchDB::checkConnection()
{
    QUrl url = m_url;
    url.setPath("/");

    m_reply = m_networkAccessManager->get(QNetworkRequest(url));
    connect(m_reply, SIGNAL(readyRead()), this, SLOT(slotCheckConnectionFinished()));
}

void QtCouchDB::slotCheckConnectionFinished()
{
    const QByteArray tst = m_reply->readAll();
    QString version = "";
    QString ret(tst);
    if (ret.contains("version"))
    {
        int end = ret.lastIndexOf("\"");
        int start = ret.indexOf("version") + 10;
        version = ret.mid(start, end-start);
    }
    emit connectionChecked(version);
}
Ich weiß, dass m_reply besser nicht global sein sollte, aber das ist noch eine andere Baustelle. Wenn da jemand eine bessere Lösung hat, immer her damit.

Anstatt das Ergebnis mit emit zurück zu geben, hätte ich viel lieber einen Funktionsaufruf wie "QString QtCouchDB::checkConnection()" bei dem ich die Antwort gleich mit zurück gebe, auch wenn ich mir damit Hänger in der GUI einfangen könnte. Ich spreche ausschließlich eine lokale DB an, bei der es keine merklichen Verzögerungen geben dürfte.

Gibt es irgend eine Möglichkeit das hin zu bekommen? Ich mache mir hier Knoten in mein Gehirn und komme einfach auf keine Lösung.

Noch eine Frage am Rande. Welches Verfahren ist besser, wenn man eine allgemeine Version der Schnittstelle schreiben würde?

Vielen Dank
Heiko
Zuletzt geändert von heikob am 12. Oktober 2011 23:34, insgesamt 1-mal geändert.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: Synchroner QNetworkAccessManager

Beitrag von RHBaum »

DU willst wirklich den GUI Thread blockieren, bis Deine Abfrage zurueckkommt ?
Stell dir vor dein Server iss nich erreichbar, willst das Prog wirklich bis zum timout (kann mehrere minuten dauern, je nach system) blockieren ???
Noch eine Frage am Rande. Welches Verfahren ist besser, wenn man eine allgemeine Version der Schnittstelle schreiben würde?
was meinst du mit Verfahren ?
Wie allgemein, sprich wie flexibel, wie unabhaengig soll deine Schnittstelle werden ?

Schnittstelle du solltest genauer spezifizieren, fuer was die Schnittstelle brauchst ...

eine Schnittstelle, mehrere Implementationen

oder

Bibliotheksschnittstelle, Zugriff auf deine eine Implementation, und die "Anwender" muessen sich anpassen ?

DU kannst da wenn Du willst, viel viel Energie reinstecken .... ohne das du wirklich was von hasst :-)

Ciao ...
heikob
Beiträge: 81
Registriert: 23. März 2005 23:20

Re: Synchroner QNetworkAccessManager

Beitrag von heikob »

Du hast schon irgendwie Recht, dass das Blockieren des GUI-Threads keine gute Idee ist. Das spricht natürlich für die asynchrone Variante. Aber irgend etwas sträubt sich in mir, bei jedem Drücken eines Buttons ein Request auszulösen und die Verarbeitung in einem eigenen Response zu behandeln. Schließlich können ja durchaus viele unterschiedliche Anfragen an die Datenbank entstehen. Aber vielleicht ist mein Sichtfeld im Moment zu eingeschränkt dafür. Ich sollte es einfach mal versuchen.

Mit Verfahren meinte ich, ob man eine synchrone oder asynchrone Schnittstelle implementieren sollte. Sie sollte so unabhängig wie möglich werden, denn wenn sie mal ausgereifter ist, möchte ich sie gerne allen zur Verfügung stellen. Es muss ja icht jeder das Rad neu erfinden. Daher möchte ich nicht gleich wie wild drauf los programmieren, sondern zuerst in Erfahrung bringen, wie es andere implementieren würden.

Ich hoffe, dass mein Anliegen damit deutlicher wurde.

HeikoB
ScyllaIllciz
Beiträge: 200
Registriert: 9. Juli 2010 19:31

Re: Synchroner QNetworkAccessManager

Beitrag von ScyllaIllciz »

Aber irgend etwas sträubt sich in mir, bei jedem Drücken eines Buttons ein Request auszulösen und die Verarbeitung in einem eigenen Response zu behandeln.
Man kann auch den Button solange deaktivieren bis der Request abgearbeit ist.
heikob
Beiträge: 81
Registriert: 23. März 2005 23:20

Re: Synchroner QNetworkAccessManager

Beitrag von heikob »

Das muss man sowieso, damit der Nutzer im Zweifelsfall keinen "Unfug" treibt. Ich denke da eher an mehrere Abfragen bzw. Updates innerhalb einer Aktion. Aber vielleicht bin ich gedanklich einfach noch nicht so weit, um es überblicken zu können.

Ich werde die Schnittstelle wohlerst einmal asynchron implementieren, wenn hier niemand mehr widerspricht. Bei Bedarf könnte man immer noch eine Schicht einziehen, die das Ganze wieder synchron macht.

HeikoB
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: Synchroner QNetworkAccessManager

Beitrag von brax »

RHBaum hat geschrieben:DU willst wirklich den GUI Thread blockieren, bis Deine Abfrage zurueckkommt ?
Stell dir vor dein Server iss nich erreichbar, willst das Prog wirklich bis zum timout (kann mehrere minuten dauern, je nach system) blockieren ???
Ehrlich gesagt, finde ich das gar nicht so abwegig. Es gibt m.E. Fälle (bzw. es gab schon Fälle bei mir), in denen ich genau dieses Verhalten haben wollte (speziell das Abfragen einer Onlinelizenz - die Anwendung soll eben einfach nicht benutzbar sein, während diese Anfrage läuft). Auch ich habe daher das Fehlen von synchroner Netzwerkkommunikation schon schmerzlich vermisst.

Ein Weg, das zu erreichen, ist die Benutzung eines weiteren QEventLoop. Allerdings ist es nicht wirklich ein besonders sauberer Weg. Du startest nach dem Abschicken des Requests einen QEventLoop (am Besten mit QEventLoop::ExcludeUserInputEvents) und stopst ihn wieder am Ende des Slots, der die Reply liest. Wie gesagt, es ist alles andere als sauber und ich kann Dir auch nicht garantieren, dass das keine ungewünschten Nebeneffekte hat...
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: Synchroner QNetworkAccessManager

Beitrag von franzf »

Ich bin da recht ungeduldig. Wenn ein Fenster plötzlich nicht mehr aktualisiert wird, und beim Überfahren mit einem anderen Fenster auch nicht mehr nachgezeichnet wird, hab ich schnell den Verdacht "eingefroren!". Ich bin dann immer recht schnell mit Alt-Strg-Esc... Für was gibt es denn Threads?
In Fällen, wo der User nicht mehr mit dem Programm interagieren soll, setzt man das MainWindow auf Disabled - fertig. Um den User nicht vollständig zu verwirren, zeigt man eine ProgressBar (oder Progressdialog) an, dass der auch erkennen kann, dass er noch bedient wird.

Softwareentwickler sollten penibel darauf achten, dass ihr Programm nicht undefiniertes Verhalten an den Tag legt. Genauso sollten sie aber auch darauf schauen, dass sie kein undefiniertes Verhalten beim Benutzer auslösen ;)
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: Synchroner QNetworkAccessManager

Beitrag von brax »

Durch den EventLoop friert die GUI nicht ein, sie wird tatsächlich weiter refresht. User inputs werden nicht abgearbeitet... (wegen ExcludeUserInputEvents).

Abgesehen davon hab ich ja bereits erwähnt, dass das alles andere als eine schöne Lösung ist.
Für was gibt es denn Threads?
Das mag ja so sein in einer idealen Welt, wo man seine Software immer komplett neu entwerfen und implementieren darf. Zurück in der Realität, in der man an einem Projekt mit etlichen millionen Zeilen Code arbeitet, was zu einem Zeitpunkt entworfen wurde, als echtes Multithreading für "normale" Anwender eher eine Bremse war als ein Gewinn, und die Firma sich einfach nicht leisten kann, ein Jahr Stillstand für ein komplettes Redesign zu riskieren, dann kann man eben der Anwendung auch kein Multithreading beibringen. Dann ist so eine - zwar unsaubere aber - pragmatische Lösung der beste Weg.
Softwareentwickler sollten penibel darauf achten, dass ihr Programm nicht undefiniertes Verhalten an den Tag legt. Genauso sollten sie aber auch darauf schauen, dass sie kein undefiniertes Verhalten beim Benutzer auslösen ;)
:?: Welches undefiniertes Verhalten? :?:
heikob
Beiträge: 81
Registriert: 23. März 2005 23:20

Re: Synchroner QNetworkAccessManager

Beitrag von heikob »

Anscheinend haben beide Varianten ihre spezifischen Vor- und Nachteile. Daher werde ich die Schnittstelle erst einmal asynchron implementieren. Falls es dann bei einigen Funktionen doch sinnvoll erscheint, kann man für ausgewählte oder alle Funktionen noch eine Schicht "davor schalten", die daraus synchrone Funktionen macht. Ich denke, so verbaut man sich keine Möglichkeiten.

Nachdem ich die rudimentärsten Funktionen programmiert habe, werde ich den Zwischenstand hier nochmal zur Diskussion stellen. Schließlich soll es ja gut werden und ich bin überzeugt, dass noch die ein oder andere gute Anregung von euch kommt, um die Sache rund zu bekommen. Schließlich soll die Schnittstelle möglichst vielen, die CouchDB verwenden wollen, die Arbeit abnehmen, selbst eine Schnittstelle programmieren zu müssen.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: Synchroner QNetworkAccessManager

Beitrag von franzf »

brax hat geschrieben:Zurück in der Realität, in der man an einem Projekt mit etlichen millionen Zeilen Code arbeitet,
Zurück in der Realität: Hier beginnt jemand gerade, an einem Problem zu basteln, es gibt keine abermillionen Codezeilen (die es bei einem Frezeitprogrammierer eh nur selten geben wird), da sollte man auf die saubere Lösungen verweisen dürfen. Wenn er jetzt am Anfang schon mit nem Hack anfängt, wo soll das dann enden?
brax hat geschrieben:
Softwareentwickler sollten penibel darauf achten, dass ihr Programm nicht undefiniertes Verhalten an den Tag legt. Genauso sollten sie aber auch darauf schauen, dass sie kein undefiniertes Verhalten beim Benutzer auslösen ;)
:?: Welches undefiniertes Verhalten? :?:
Wenn eine GUI plötzlich nicht mehr reagiert, nicht mehr nachzeichnet, denkt sich der User schnell "eingefroren - toll". Der eine User sitzt es eben aus, der andere schießt es ab (Strg+Alt+Esc). Der Programmierer kann sich auf das Verhalten des Users nicht verlassen -> undefiniert! Wenn man das Problem lösen kann, ohne den User vor einem nicht mehr reagierenden Programm sitzen zu lassen, sollte man das auch tun.

Dass das mit der neuen EventLoop nicht passiert, mag sein (hab ich noch nie gemacht...), schön ist es halt nicht.
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: [gelöst] Synchroner QNetworkAccessManager

Beitrag von brax »

Ok, ich gebe zu, das war vielleicht etwas sehr provokativ, sorry. Ich finde bloß dieses von oben herab Gehabe ("warum willst Du denn sowas machen, ist doch totaler Mist"), dass viele Foristen an den Tag legen, immer sehr nervig. Ich wollte ja bloß, sagen, dass es durchaus gute Gründe für synchrone Netzwerkkommunikation geben kann. Netzwerk ist nicht immer das unberechenbare Internet.

Ein vielleicht besseres Beispiel wäre ein Frontend für eine Gridsoftware z.B. Sun Grid Engine. Man kann sich sicher sein, dass das Programm in einem LAN benutzt wird und die Verfügbarkeit des Servers im Bereich von sechs neunen liegt. Wenn dann ein Job abgeschickt werden soll, möchte ich eben nicht den Overhead haben, dass für jeden Job erstmal die GUI disabled wird, der der Signal/Slot Mechanismus angeworfen wird, um dann die GUI gleich wieder zu enablen. Insbesondere dann nicht wenn ich einige tausend Jobs abschicken möchte.... Da kann ich doch echt besser damit leben, dass in 0.000001 der Fällen ein Timeout auftritt (dass ich dann auch selbst bestimmen kann und im Millisekundenbereich liegt).
Du kannst nun natürlich sagen, dass man dann eben nicht Qt benutzen soll. Mag sein. Aber wenn das Programm eh schon Qt benutzt, ist es doch am Naheliegensten. Und warum wird die Möglichkeit nicht einfach angeboten?
Antworten