Seite 1 von 1

Problem mit QTcpServer/QTcpSocket

Verfasst: 16. Dezember 2009 14:53
von rurseekatze
Hallo,

ich will mir eine einfache Chatanwendung programmieren. Den Client habe ich soweit fertig gestellt und nun bin ich dabei, den Server zu schreiben. Allerdings habe ich folgendes Problem, und ich verstehe einfach nicht, warum es nicht klappen will:

Der Client kann sich erfolgreich mit dem Server verbinden, und der Server schickt "hello new client", was der Client auch empfängt. Bis "new client wants to connect and sended NEW" läuft auch alles ohne Probleme durch und die entsprechenden Meldungen erscheinen auch. Schicke ich nun mit dem Client etwas an den Server, wird readyRead() ausgelöst und "new client wants to connect and sended NEW" ausgegeben, der Client empfängt jedoch dann nichts und "c" wird nicht ausgegeben. Nehme ich das raus, hängt er beim Senden, wieder wird "c" nicht ausgegeben und der Client empfängt nichts.

Ich habe einfach keine Ahnung, wo der Fehler liegt, denn am Client liegt es anscheinend nicht und der Server kann auch versenden und das readyRead() Signal wird ausgelöst.


Hier noch der Code:
italk.cpp

Code: Alles auswählen

#include "italk.h"

italk::italk(QMainWindow *parent) : QMainWindow(parent)
{
	setupUi(this);
	connect(actionAbout, SIGNAL (triggered()), this, SLOT(showAbout()));
	connect(actionAboutQt, SIGNAL (triggered()), qApp, SLOT(aboutQt()));
	connectionStatusBar->showMessage(QString(tr("Nicht verbunden.")));
	setServerOnline();
}

italk::~italk()
{
}

void italk::setServerOnline()
{
	commandServer = new QTcpServer(this);
	commandServer->listen(QHostAddress::Any,51238);
	connect(commandServer, SIGNAL(newConnection()), this, SLOT(newClient()));
}

void italk::newClient()
{
	cout << "new client" << endl;
	if (commandServer->hasPendingConnections())
	{
		QTcpSocket *clientSocket = commandServer->nextPendingConnection();
		connect(clientSocket, SIGNAL(readyRead()), this, SLOT(recieveCommand()));
		cout << "a" << endl;
		clientSocket->write("hello new client");
		cout << "b" << endl;
	}
	else
		cout << "no pending connections";
}

void italk::recieveCommand()
{
	cout << "new client wants to connect and sended NEW" << endl;
	QString message(clientSocket->readAll());
	cout << "c" << endl;
	cout << message.toStdString() << endl;
	clientSocket->write("OK");
}

italk.h

Code: Alles auswählen

#ifndef italk_H
#define italk_H

#include "ui_italk.h"
#include "logfile.h"
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <QtGui>
#include <QString>
#include <QTranslator>
#include <QTimer>
#include <QKeyEvent>
#include <QtNetwork>
#include <QDataStream>
#include <QByteArray>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QTcpServer>

using namespace std;

class italk : public QMainWindow, public Ui::MainWindow
{
	Q_OBJECT
	public:
		italk(QMainWindow *parent = 0);
		~italk();
		QTcpServer *commandServer;
		QTcpSocket *clientSocket;
	private slots:
		void setServerOnline();
		void newClient();
		void recieveCommand();
};

#endif

Verfasst: 16. Dezember 2009 16:58
von Christian81
Zwei Dinge
1. readyRead() wird irgendwann aufgerufen - es müssen noch nicht alle Daten vorliegen. Also nicht wundern wenn Du vom Client nicht alles bekommst. Besser (wenn es Text ist) auf canReadLine() checken ob auch wirklich eine komplette Zeile angekommen ist
2. QTcpSocket/Server() bzw. die darunterliegende QIODevice cacht die Daten und sie werden nur versandt wenn der Puffer voll ist bzw. die QIODevice Lust hat. Wenn man sicher gehen will dass es wirklich gesendet wird -> flush()

Verfasst: 16. Dezember 2009 17:46
von rurseekatze
Christian81 hat geschrieben:Zwei Dinge
1. readyRead() wird irgendwann aufgerufen - es müssen noch nicht alle Daten vorliegen. Also nicht wundern wenn Du vom Client nicht alles bekommst. Besser (wenn es Text ist) auf canReadLine() checken ob auch wirklich eine komplette Zeile angekommen ist
Werd ich mal ausprobieren, aber das ist eigentlich nicht das Problem. Das Problem ist, dass ich sowohl nicht senden, als auch nichts empfangen kann, jedenfalls wenn es in der Funktion steht, die von readyRead aufgerufen wird. In der anderen Funktion klappt das Versenden komischerweise, denn der Client erhält korrekt das "hello new client".
Christian81 hat geschrieben: 2. QTcpSocket/Server() bzw. die darunterliegende QIODevice cacht die Daten und sie werden nur versandt wenn der Puffer voll ist bzw. die QIODevice Lust hat. Wenn man sicher gehen will dass es wirklich gesendet wird -> flush()
Hab ich jetzt noch nicht ausprobiert, aber das Problem ist, dass das Programm schon beim readAll() bzw. beim write() abstürzt. Daher wird es gar nicht bis zum flush() kommen.

Verfasst: 16. Dezember 2009 17:50
von Christian81
Ok - C++ Basics würde ich sagen...

Code: Alles auswählen

QTcpSocket *clientSocket = commandServer->nextPendingConnection(); 
Das ist sicher nicht das was Du willst und somit ist deine member-Variable clientSocket nicht initialisiert...

Verfasst: 16. Dezember 2009 17:56
von rurseekatze
Wie würde es denn richtig lauten?
Habe das so schon in verschiedenen Beispielen im Internet so gesehen.
Bin noch nicht so erfahren mit C++, mache es mehr mit learning by doing und ausprobieren, und bisher habe ich so auch immer erreicht, was ich wollte.

Verfasst: 16. Dezember 2009 18:03
von Christian81
Meinen Post durchlesen und fertig!
Du erzeugst eine neue Variable mit dem gleichen Namen wie deine member-Variable - also ist deine Member-Variable unintialisiert!!

Verfasst: 16. Dezember 2009 18:15
von rurseekatze
Welche Variable hat denn einen gleichen Namen wie eine Membervariable? Irgendwie stehe ich gerade auf dem Schlauch.

Verfasst: 16. Dezember 2009 19:15
von MiKla
hier:

Code: Alles auswählen

class italk : public QMainWindow, public Ui::MainWindow
{
   Q_OBJECT
   public:
      italk(QMainWindow *parent = 0);
      ~italk();
      QTcpServer *commandServer;
      QTcpSocket *clientSocket;
   private slots:
      void setServerOnline();
      void newClient();
      void recieveCommand();
}; 
und hier:

Code: Alles auswählen

QTcpSocket *clientSocket = commandServer->nextPendingConnection(); 
Michael

Verfasst: 16. Dezember 2009 20:21
von rurseekatze
Danke! Jetzt hab ich's verstanden. Hab da wohl verschiedene Beispiele vermischt und dann ist soetwas herausgekommen.

Hab jetzt einfach

Code: Alles auswählen

QTcpSocket *clientSocket = commandServer->nextPendingConnection(); 
in
clientSocket = commandServer->nextPendingConnection();
geändert und es funktioniert perfekt.