Fragen zu QTcpSocket und QTcpServer

Alles rund um die Programmierung mit Qt
Antworten
Toni0815
Beiträge: 5
Registriert: 23. November 2009 20:48

Fragen zu QTcpSocket und QTcpServer

Beitrag von Toni0815 »

Hallo Leute,
also, ich habe gerade begonnen ein kleines Chatprogrammen zu erstellen und dabei sind bei mir Unklarheiten aufgetaucht.

Der Chat, den ich machen will besteht aus zwei Programmen, einem Sender und einem Empfänger.

So bin ich vorgegangen:

Sender-Programm
----------------------

1. Ich erstelle ein QTcpSocket-Objekt und erstelle einen Signal/Slot um herauszufinden, ob die verbindung besteht.

Code: Alles auswählen

tcpSocket = new QTcpSocket(this);
QObject::connect(tcpSocket, SIGNAL(connected()), this, SLOT(verbindungAufgebaut()));
2. Ich baue die Verbindung zu host auf

Code: Alles auswählen

tcpSocket->connectToHost( string_host, int_port );
3. Ich erzeuge einen Stream, den ich dann auf tcpSocket ausgebe

Code: Alles auswählen

QTextStream stream_nachricht(tcpSocket);
  stream_nachricht << string_nachricht << endl;



Empfänger-Programm
----------------------

1. Ich erzeuge ein QTcpServer-Objekt und ein QTcpSocket-Objekt und weise ihm SIGNALS/SLOTS zu um eine reinkommende Verbindung zu erkennen und um die Daten auszulesen

Code: Alles auswählen

tcpServer = new QTcpServer(this);
tcpSocket = new QTcpSocket(tcpServer);
QObject::connect(tcpServer, SIGNAL(newConnection()), this, SLOT(verbindungAufgebaut()));
    QObject::connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(nachrichtEmpfangen()));
2. Ich weise dem tcpServer-Objekt einen Adapter und einen Port zu, den er abhören soll

Code: Alles auswählen

tcpServer->listen(QHostAddress::Any,int_port);

Das funktioniert schon
-------------------------
Am Server wird bei Verbindung das SINAL newConnection() ausgelöst, also eine Verbindung wird aufgebaut, das funktioniert bei localhost, LAN, Hamachi und übers internet. Soweit alles ok.


Das funktioniert nicht
-------------------------
Am Server wird das SIGNAL readyRead() nicht ausgelöst und ich kann die Daten nicht empfangen.
Ich kann nicht auslesen wie die IP des verbundenen Hosts ist.


Nun meine Fragen
---------------------
1. Dient das QTcpServer-Objekt nur dazu um an einem Port zu horchen ?
2. Muss ich am Server (wie schon gemacht) ein QTcpSocket-Objekt erstellt werden?
3. Ich muss doch irgendwie dem QTcpSocket-Objekt die Eigenschaften des QTcpServer-Objekt übergeben, wie z.B Port auf dem Daten ankommen usw., wie funktioniert das genau?
4.Wie kann ich am Server die IP des Verbundenen Client auswerten und als String verwenden?
5. Wie genau müsste der Empfang von Daten funktionieren?





Vielen Dank im Vorraus,
ich hoffe ihr könnt mir bei meinem N00b-Problem helfen.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Schau dir mal den Fortune-Server & -Client an.

http://doc.trolltech.com/4.4/examples.html#network
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

> 1. Dient das QTcpServer-Objekt nur dazu um an einem Port zu horchen ?
.. und natürlich auch die Verbindung(en) aufzubauen..

> 2. Muss ich am Server (wie schon gemacht) ein QTcpSocket-Objekt erstellt werden?
Nein.. siehe http://doc.trolltech.com/4.5/network-fortuneserver.html

> 3. Ich muss doch irgendwie dem QTcpSocket-Objekt die Eigenschaften des QTcpServer-Objekt übergeben[...]
Nein.. siehe http://doc.trolltech.com/4.5/network-fortuneserver.html

> 4.Wie kann ich am Server die IP des Verbundenen Client auswerten und als String verwenden?
siehe Doku: http://doc.trolltech.com/4.5/qabstractsocket.html

> 5. Wie genau müsste der Empfang von Daten funktionieren?
Kommt auf dein Protokoll an.. du musst selbst definieren, wie die Daten des Streams(!) interpretiert werden müssen. Für ein ASCII "HelloWorld" genügt readAll().. (siehe die zahlreichen read-Methoden von http://doc.trolltech.com/4.5/qtcpsocket-members.html)
Toni0815
Beiträge: 5
Registriert: 23. November 2009 20:48

Beitrag von Toni0815 »

Danke für eure Antworten,

aber könntet ihr mir mal vom sinn her schritt für schritt erklären wie so eine Verbindung abläuft...

Ich stell mir das so vor.

1. QTcpSocktet-Objekt baut Verbindung zum Host mit gewünschter IP un Port auf.

2. QTcpServer-Objekt im Server "horcht" an einem Port und akzeptiert die Verbindung, somit besteht die Verbindung und newConnection() wird ausgelöst.

??? aber wie geht es vom Sinn her weiter ??? könntet ihr das bitte mal beschreiben...



MfG Toni0815 :-)
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

void QTcpServer::newConnection ()
QTcpSocket * QTcpServer::nextPendingConnection ()
void QIODevice::readyRead ()
QByteArray QIODevice::readAll ()
qint64 QIODevice::write ( const QByteArray & byteArray )
void QIODevice::bytesWritten ( qint64 bytes )
void QAbstractSocket::close ()
Toni0815
Beiträge: 5
Registriert: 23. November 2009 20:48

Beitrag von Toni0815 »

Code: Alles auswählen

QTcpSocket * QTcpServer::nextPendingConnection () 
also hiermit übergebe ich die aktuelle Verbindung des Servers an den Socket
aber leider wird bei mir readyRead nicht ausgelöst :-(

Ich poste nun mal das, was ich bis jetzt gemacht habe, vielleicht kann mir ja einer von euch Experten einen Tipp geben :-)

Hier der Code des Server-Programms
---------------------------------------------

Code: Alles auswählen

#include "netzwerknachrichtempfaenger.h"
#include "ui_netzwerknachrichtempfaenger.h"

NetzwerkNachrichtEmpfaenger::NetzwerkNachrichtEmpfaenger(QWidget *parent)
    : QDialog(parent), ui(new Ui::NetzwerkNachrichtEmpfaenger)
{
    ui->setupUi(this);

    tcpServer = new QTcpServer(this);
    tcpServer->listen(QHostAddress::Any,55555);
    tcpSocket = new QTcpSocket(this);
   
    QObject::connect(tcpServer, SIGNAL(newConnection()), this, SLOT(verbindungAufgebaut()));
    QObject::connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(nachrichtEmpfangen()));
}

NetzwerkNachrichtEmpfaenger::~NetzwerkNachrichtEmpfaenger()
{
    delete ui;
    delete tcpServer;
}

void NetzwerkNachrichtEmpfaenger::nachrichtEmpfangen(void)
{
    ui->feldNachrichten->addItem("Test, ob readyRead ausgelöst wurde"); 
}

void NetzwerkNachrichtEmpfaenger::verbindungAufgebaut(void)
{
    tcpSocket = tcpServer->nextPendingConnection();
}



Hier der Code des Client-Programms
---------------------------------------------

Code: Alles auswählen

#include "netzerknachrichtsender.h"
#include "ui_netzerknachrichtsender.h"

NetzerkNachrichtSender::NetzerkNachrichtSender(QWidget *parent)
    : QDialog(parent), ui(new Ui::NetzerkNachrichtSender)
{
    ui->setupUi(this);

    tcpSocket = new QTcpSocket(this);
    QObject::connect(tcpSocket, SIGNAL(connected()), this, SLOT(verbindungAufgebaut()));
    QObject::connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(verbindungGetrennt()));
}


NetzerkNachrichtSender::~NetzerkNachrichtSender()
{
    delete ui;
    delete tcpSocket;
}


void NetzerkNachrichtSender::on_buttonSenden_clicked()
{
      string_host   = ui->ipFeld->text();
      string_port   = ui->portFeld->text();
      int_port      = string_port.toInt(&bool_eingabeOk, 10);

      if(!bool_eingabeOk)
      {
            ui->portFeld->setText("55555");
            return;
      }

      tcpSocket->connectToHost( string_host, int_port );
      string_nachricht = ui->nachrichtFeld->text();

      if ( string_nachricht.isEmpty() )
      {
            return;
      }

      nachrichtSenden();

}

void NetzerkNachrichtSender::verbindungAufgebaut(void)
{
    ui->statusFeld->setText("Connected to "+tcpSocket->peerName()+"::"+QString::number(tcpSocket->peerPort(),10));
    tcpSocket->write("Test");
}


void NetzerkNachrichtSender::verbindungGetrennt(void)
{
    ui->statusFeld->setText("Disconnected");
}


void NetzerkNachrichtSender::nachrichtSenden(void)
{
    if ( string_nachricht.isEmpty() || string_port.isEmpty() || string_host.isEmpty() )
    {
        return;
    }
    QTextStream stream_nachricht(tcpSocket);
    stream_nachricht << string_nachricht << endl;
}


Mfg Toni0815
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Code: Alles auswählen

tcpSocket = new QTcpSocket(this);
    QObject::connect(tcpSocket, SIGNAL(connected()), this, SLOT(verbindungAufgebaut()));
    QObject::connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(verbindungGetrennt())); 
Dieser Code im Konstruktor ist komplett sinnfrei... schau dir mal folgendes Beispiel an:

http://doc.trolltech.com/4.5/network-fo ... r-cpp.html

Und nun kannst du dir selbst die Frage stellen: Wer erstellt den QTcpSocket und wann muessen die Signals des Sockets zu den eigenen Slots verbunden werden?

[edit]
Deine Frage 2 (ob beim Server der Socket selbst erstellt werden muss) habe ich uebrigens schon lange mit nein beantwortet..
Toni0815
Beiträge: 5
Registriert: 23. November 2009 20:48

Beitrag von Toni0815 »

Dieser Code im Konstruktor ist komplett sinnfrei... schau dir mal folgendes Beispiel an:
Wäre super, wenn du mal zu deinen Antworten eine Begründung hinzuschreiben würdest, warum kann ich im Konstruktor kein Objekt erzeugen und keine Signal/Slots zuweisen?
Was soll daran sinnfrei sein, oder gibt es bei so einem Socketobjekt eine besonderheit .....
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Die fehlende Begruendung begruende ich damit, dass der Fehler in deinem Programm auf fehlendes C++-Grundwissen und mangelnder Umgang mit der Doku zurueckzufuehren ist.

Folgende Erklaerung:
Auch fuer jemanden ohne Qt-Erfahrung sollte es ersichtlich sein, dass im Konstruktor eine Instanz erzeugt wird und der Pointer darauf jedoch spaeter ueberschrieben wird:

Code: Alles auswählen

// im C-Tor
  tcpSocket = new QTcpSocket(this); 
// in verbindungAufgebaut:
  tcpSocket = tcpServer->nextPendingConnection(); 
tcpSocket zeigt damit damit auf ein anderes Objekt, welches eben nicht mit deinen Slots verbunden ist.

kommen wir zum Qt-Teil: sowohl im Fortune-Server Beispiel:

Code: Alles auswählen

void Server::sendFortune()
 {
     ...
     QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
     connect(clientConnection, SIGNAL(disconnected()),
             clientConnection, SLOT(deleteLater()));
als auch in der Doku (http://doc.trolltech.com/4.5/qtcpserver ... Connection)
The socket is created as a child of the server
steht, dass der Socket von QTcpServer erstellt wird..

Ist das genug Begruendung?
Toni0815
Beiträge: 5
Registriert: 23. November 2009 20:48

Beitrag von Toni0815 »

danke erstmal ...
ja, das macht sinn ... C++ Vorlesung ist schon ein paar Semester her :-)
ich werds gleich mal ändern
Antworten