QT Multithreaded Statefull Server

Alles rund um die Programmierung mit Qt
Antworten
psy_cho
Beiträge: 6
Registriert: 5. November 2009 15:36

QT Multithreaded Statefull Server

Beitrag von psy_cho »

------
Zuletzt geändert von psy_cho am 6. November 2009 23:19, insgesamt 1-mal geändert.
Mani99
Beiträge: 244
Registriert: 15. April 2009 10:46
Wohnort: München

Beitrag von Mani99 »

Du solltest event. in der run() methode noch ein "exec()" aufrufen, dann lebt der thread "etwas" länger!
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Der Thread lebt schon lange genug... obwohl ich die Eventloop-Methode für viel eleganter (echte Statemachine) halte, denke ich auch es müsste eine Lösung auf diesem Weg geben. Die einzigen Punkte die ich sehe sind folgende:

1. Nach dem connect würde ich auf die Verbindung warten:

Code: Alles auswählen

sock->connectToHost(QString("127.0.0.1"),(qint16)1643); 
sock->waitForConnected(-1);
Keine Ahnung was bei einem "write(..)" im Zustand "QAbstractSocket::ConnectingState" geschieht...

2. "sock->flush();" ist IMHO unnötig... nach waitForBytesWritten() gibt es ja nichts mehr zu senden..
dikilroy
Beiträge: 7
Registriert: 14. Januar 2009 22:08

Beitrag von dikilroy »

Hi,

ich vermute einem "DeadLock".

Kannst Du bitte noch den Server dazu posten? (virtualmanageragent.h, virtualmanageragent.cpp??) Je nachdem in welcher Reihenfolge das Empfangen und Senden geschieht, kann es sein, dass beide Prozesse aufeinander warten.

Hast Du mal im Debug geschaut wo der Client stecken bleibt? In waitForBytesWritten oder in waitForReadyRead?

Zum Thema flush() sagt die Qt Doku:
... In the absence of an event loop, call waitForBytesWritten() instead.
Also weglassen und waitForBytesWritten aufrufen! Oder -meine Meinung- direkt nach dem write() und anschliessend waitForBytesWritten() aufrufen. Wird aber nichts am Problem ändern.

Grüße
André

PS
Hab sowas noch nie mit Qt Mitteln gemacht, sondern mit Standard C Funktionen ...
psy_cho
Beiträge: 6
Registriert: 5. November 2009 15:36

Beitrag von psy_cho »

----------------------------
Zuletzt geändert von psy_cho am 6. November 2009 23:19, insgesamt 1-mal geändert.
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

Gibts nen Grund dafür, dass du so eisern drauf bestehst, keine Signals & Slots zu verwenden?
psy_cho
Beiträge: 6
Registriert: 5. November 2009 15:36

Beitrag von psy_cho »

--------------------------------------------------------------------------
Zuletzt geändert von psy_cho am 6. November 2009 23:19, insgesamt 1-mal geändert.
lepsai
Beiträge: 573
Registriert: 14. September 2004 21:33
Wohnort: Berlin
Kontaktdaten:

Beitrag von lepsai »

psy_cho hat geschrieben:Ich hab damit in Verbindung von OpenGL und QT sehr schlechte Erfahrungen gemacht. Was laut doku hätte funktionieren müssen tat es nicht wie ihm geheißen.
Ich hab nix gegen echte Signals, so wie sie zwischen Posix Threads oder Prozessen gesendet werden können. Weil ich da entscheide in welchem Thread diese abgearbeitet werden.
Ich bin generell kein freund dieser Callback Konzepte, da man bei multithreaded Anwendungen recht schnell aus den Augen verlieren kann in welchem Kontext den nun eine Methode aufgerufen wird.

Ich tendiere eher zu transparentem Informationsfluss innerhalb einer Anwendung.

Ich hab natürlich auch nichts gegen eine Signal Slot Lösung. Wenn sie multithreaded arbeitet und gut funktioniert.

Mfg

Marc
Ich würde an deiner Stelle genauestens überlegen, ob du eine multi-threaded Lösung überhaupt brauchst. Meine Erfahrung zeigt, dass die Benutzung von mehr als 2 Threads innerhalb einer Anwendung oft die Folge von falschen architektonischen Entscheidungen ist...
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

nicht-transparenter Code und dein Code haben was gemeinsam: beide funktionieren nicht ... :roll:

Mal abgesehen davon, dass du (soweit wir in das Projekt sehen) wirklich noch nirgends ein Thread benötigen würdest, habe ich dafür keine 24h, keine 20min sondern gerademal 5-10min benötigt:

Code: Alles auswählen

#ifndef _PING_
#define _PING_
#include <QThread>
class Ping: public QThread
{
  public:
    virtual void run();
};
#endif

Code: Alles auswählen

#ifndef _PONG_
#define _PONG_
#include <QThread>
class Pong: public QThread
{
  public:
    virtual void run();
};
#endif

Code: Alles auswählen

#include <QDebug>
#include <QTcpSocket>
#include <QTcpServer>
#include "ping.h"

void Ping::run()
{
  QTcpServer primaryServer;
  qDebug() << "Ping: warte auf Client";
  primaryServer.listen(QHostAddress::Any,1643);
  primaryServer.waitForNewConnection(-1);
  QTcpSocket* newConnection = primaryServer.nextPendingConnection();
  newConnection->waitForConnected(-1);
  qDebug() << "Ping: Verbunden";
  while (1) {
    qDebug() << "Ping: sende ping";
    newConnection->write("ping");
    newConnection->waitForBytesWritten(-1);
    qDebug() << "Ping: warte auf Antwort";
    newConnection->waitForReadyRead(-1);
    qDebug() << "Ping: Antwort erhalten" << newConnection->readAll();
  }
}

Code: Alles auswählen

#include <QDebug>
#include <QTcpSocket>
#include "pong.h"

void Pong::run()
{
  QTcpSocket newConnection;
  do {
    newConnection.connectToHost("localhost",1643);
  } while (!newConnection.waitForConnected(1000));
  qDebug() << "Pong: Verbunden";
  while (1) {
    qDebug() << "Pong: warte auf Antwort";
    newConnection.waitForReadyRead(-1);
    qDebug() << "Pong: Antwort erhalten" << newConnection.readAll();
    qDebug() << "Pong: sende pong";
    newConnection.write("pong");
    newConnection.waitForBytesWritten(-1);
  }
}

Code: Alles auswählen

#include <QCoreApplication>

#include "ping.h"
#include "pong.h"

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

  Ping t1;
  Pong t2;
  t1.start();
  t2.start();
  return app.exec();
}
hth..

[EDIT] PS.
Qt kann nicht alles und ist auch nicht fehlerfrei, aber OpenGL/Qt/Signals/Slots arbeiten (bei richtiger Anwendung) hervorragend...
psy_cho
Beiträge: 6
Registriert: 5. November 2009 15:36

Beitrag von psy_cho »

@solarix

Früher hätte ich mir die Mühe gemacht, dass mit dir zu diskutieren.
Mittlerweile sag ich einfach "Danke", den Rest kannst du dir denken.
Auf solch unqualifizierte Antworten leg ich keinen Wert.

Wieder eine wertvolle Erfahrung gemacht hier.

In diesem Sinne.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Soweit so gut. Das Problem taucht jetzt beim Auslesen auf.
Warte ich mit QTcpSocket::waitForReadyRead(-1) blockierend auf Input vom Socket ist der Ofen aus. Der Thread blockiert.
Das Beispiel funktioniert doch, oder nicht?
psy_cho
Beiträge: 6
Registriert: 5. November 2009 15:36

Beitrag von psy_cho »

Mag sein, dass es funktioniert.
Aber es ist wieder nicht das was ich suche. Ich will die neu aufgebaute Verbindung einem Thread übergeben, der diese bearbeitet. Ein vorgehen, was sich über Jahr hinweg erfolgreich behauptet hat. Also kann es net so schlecht sein.
Das Problem was ich festgestellt hab ist das waitForReadyRead nie zurück kehrt. Muss es aber, da Daten über die Verbindung gelaufen sind. Kann man ja mit Wireshark, etc prüfen.
psy_cho
Beiträge: 6
Registriert: 5. November 2009 15:36

Beitrag von psy_cho »

Jetzt schlägt's aber 13.
Ich hab dein Beispiel nochmal so Modifiziert, dass es die neue Verbindung in einen eigenen Thread packt. Und es geht.
Ich mach in meinem Code semantisch 1:1 das gleiche.
Aber der waitForReadyRead kommt net zurück. Ich glaub ich
leg das Projekt nochmal neu an.
Vllt stimmt da irgendwas im Projekt file net
Antworten