QTcpServer

Alles rund um die Programmierung mit Qt
Antworten
tamasi
Beiträge: 45
Registriert: 5. Juli 2007 15:49

QTcpServer

Beitrag von tamasi »

Hi,

ich möchte ein Anwendung mit Qt und TCP/IP programmieren.
Derzeit habe ich ein Problem, dass mein Server irgendwie nicht mitbekommt wenn der Client abschmiert.

Ich dachte ich könnte das mit error() und state() abfangen, aber den Server interessiert das irgendwie Null ob ich da beim Client testweise mal das Verbidnungskabel kappe. Der Client heult sofort rum, zeigt mir die korrekte Fehlermeldung an Serververbindng verloren, keine Serverberbindung usw, der Server nicht.
Arbeiten diese Funktionen beim Server anders, bzw der TcpSocket, der mir die Verbindung verwaltet?
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Der Client bringt eine Fehlermeldung, wenn er sendet oder wenn er empfangen soll? Der Server bringt immer keine Fehlermeldung, weder beim senden, noch beim empfangen?
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

verbinde QTcpServer::newConnection() mit einem Slot deiner Klasse.

Code: Alles auswählen

connect(this->m_pTcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
In diesem Slot dann das QTcpSocket::disconnected()-Signal verbinden.

Code: Alles auswählen

void MyClass::newConnection()
{
	this->m_pTcpSocket = this->m_pTcpServer->nextPendingConnection();
	connect(this->m_pTcpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
	connect(this->m_pTcpSocket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));

}
Mit dem disconnect-Signal bekommt man dann auch das Ziehen des Netzwerkkabels mit.


Ciao,
Sephral
tamasi
Beiträge: 45
Registriert: 5. Juli 2007 15:49

Beitrag von tamasi »

Ich habe 2 kleine Programme.

Der Server zählt nur die eingehenden Verbindungen, nimmt per incomingConnections neue entgegen etc.

Der Code für den TCP Teil sieht folgendermassen aus:

Code: Alles auswählen

FortuneServer::FortuneServer(QObject *parent)
    : QTcpServer(parent)
{ i=0;
  this->setMaxPendingConnections(3); 
  connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(changed(QAbstractSocket::SocketState)));
  
}

void FortuneServer::incomingConnection(int socketDescriptor)
{   
   i+=1; 
  QTcpSocket* tcpSocket= new QTcpSocket();
    if (!tcpSocket->setSocketDescriptor(socketDescriptor)) {
      emit fehler("SocketDescriptor"); 
        //error(tcpSocket->error(3));
        return;
    }
    else {
      emit update(i);
    }
     tcpSocket->state();
    int r=connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(changed(QAbstractSocket::SocketState)));
    int ret=connect(tcpSocket, SIGNAL(serverError(QAbstractSocket::SocketError)), this, SLOT(error1(QAbstractSocket::SocketError)));
    /*FortuneThread *thread = new FortuneThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    connect(thread, SIGNAL(error(QString)), this, SLOT(error(QString)));
    i+=1;
    emit update(i);
    thread->start();*/
}

void FortuneServer::error1(QAbstractSocket::SocketError socketError) {
  switch (socketError) {
    case QAbstractSocket::ConnectionRefusedError:
      emit fehler("ConnectionRefusedError");
      break;
    case QAbstractSocket::RemoteHostClosedError:
      emit fehler("RemoteHostClosedError");
      break;
    case QAbstractSocket::HostNotFoundError:
      emit fehler("HostNotFoundError");
      break;
    case QAbstractSocket::SocketAccessError:
      emit fehler("SocketAccessError");
      break;
    case QAbstractSocket::SocketResourceError:
      emit fehler("SocketResourceError");
      break;
    case QAbstractSocket::SocketTimeoutError:
      emit fehler("SocketTimeoutError");
      break;
    case QAbstractSocket::DatagramTooLargeError:
      emit fehler("DatagramTooLargeError");
      break;
    case QAbstractSocket::NetworkError:
      emit fehler("NetworkError");
      break;
    case QAbstractSocket::AddressInUseError:
      emit fehler("AddressInUseError");
      break;
    case QAbstractSocket::SocketAddressNotAvailableError:
      emit fehler("SocketAddressNotAvailableError");
      break;
    case QAbstractSocket::UnsupportedSocketOperationError:
      emit fehler("UnsupportedSocketOperationError");
      break;
    case QAbstractSocket::UnknownSocketError:
      emit fehler("UnknownSocketError");
      break;
  }
}

void FortuneServer::changed(QAbstractSocket::SocketState s_state) {
  switch (s_state) {
    case QAbstractSocket::UnconnectedState:
      emit h_state("UnconnectedState");
      break;
    case QAbstractSocket::HostLookupState:
      emit h_state("HostLookupState");
      break;
    case QAbstractSocket::ConnectingState:
      emit h_state("ConnectingState");
      break;
    case QAbstractSocket::ConnectedState:
      emit h_state("ConnectedState");
      break;
    case QAbstractSocket::BoundState:
      emit h_state("BoundState");
      break;
    case QAbstractSocket::ClosingState:
      emit h_state("ClosingState");
      break;
    case QAbstractSocket::ListeningState:
      emit h_state("ListeningState");
      break;
    default:
      break;
  }
}
Der Client versucht logischerweise eine Vrbindung zu dem Server zu kreieren.

Code: Alles auswählen

TCPClient::TCPClient(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
    ui.setupUi(this);

    ui.progressBar->hide();
    ui.progressBar_2->hide();
    ui.progressBar_3->hide();

    connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
    connect(ui.pushButton_2, SIGNAL(clicked()), this, SLOT(on_pushButton_2_clicked()));
    connect(ui.pushButton_3, SIGNAL(clicked()), this, SLOT(on_pushButton_3_clicked()));
    connect(ui.pushButton_4, SIGNAL(clicked()), this, SLOT(on_pushButton_4_clicked()));
    connect(ui.pushButton_5, SIGNAL(clicked()), this, SLOT(on_pushButton_5_clicked()));
    connect(ui.pushButton_6, SIGNAL(clicked()), this, SLOT(on_pushButton_6_clicked()));
    connect(&TcpSocket1, SIGNAL(connected()), this, SLOT(verbSteht1()));
    connect(&TcpSocket2, SIGNAL(connected()), this, SLOT(verbSteht2()));
    connect(&TcpSocket3, SIGNAL(connected()), this, SLOT(verbSteht3()));
    connect(&TcpSocket1, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error1(QAbstractSocket::SocketError)));
    connect(&TcpSocket2, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error2(QAbstractSocket::SocketError)));
    connect(&TcpSocket3, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error3(QAbstractSocket::SocketError)));
    connect(&TcpSocket1, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(changed(QAbstractSocket::SocketState)));
    connect(&TcpSocket1, SIGNAL(disconnected()), this, SLOT(disco1()));
    connect(&TcpSocket2, SIGNAL(disconnected()), this, SLOT(disco2()));
    connect(&TcpSocket3, SIGNAL(disconnected()), this, SLOT(disco3()));
}

TCPClient::~TCPClient()
{

}
void TCPClient::changed(QAbstractSocket::SocketState s_state) {
  if (true) {
    ui.label->setText("dfgjfdklgj");
  }
}

void TCPClient::on_pushButton_clicked() {
  TcpSocket1.connectToHost("192.168.36.153", 6178);
  ui.label->setText("Verbinde mit Server...");
  ui.progressBar->show();
  ui.pushButton_4->setEnabled(true);
}

void TCPClient::on_pushButton_2_clicked() {
  TcpSocket2.connectToHost("LocalHost", 6178);
  ui.label_2->setText("Verbinde mit Server...");
  ui.progressBar_2->show();
  ui.pushButton_5->setEnabled(true);
}

void TCPClient::on_pushButton_3_clicked() {
 TcpSocket3.connectToHost("LocalHost", 6178);
 ui.label_3->setText("Verbinde mit Server...");
 ui.progressBar_3->show();
 ui.pushButton_6->setEnabled(true);
}
void TCPClient::on_pushButton_4_clicked() {
 TcpSocket1.disconnectFromHost ();
 ui.label->setText("Verbindung manuell unterbrochen.");
}

void TCPClient::on_pushButton_5_clicked() {
 TcpSocket2.disconnectFromHost ();
 ui.label_2->setText("Verbindung manuell unterbrochen.");
}

void TCPClient::on_pushButton_6_clicked() {
 TcpSocket3.disconnectFromHost ();
 ui.label_3->setText("Verbindung manuell unterbrochen.");
}

void TCPClient::verbSteht1() {
  ui.progressBar->hide();
  ui.label->setText("Verbindung hergestellt.");
}

void TCPClient::verbSteht2() {
  ui.progressBar_2->hide();
  ui.label_2->setText("Verbindung hergestellt.");
}

void TCPClient::verbSteht3() {
  ui.progressBar_3->hide();
  ui.label_3->setText("Verbindung hergestellt.");
}

void TCPClient::disco1() {
  ui.progressBar->hide();
  ui.label->setText("Verbindung mit dem Server unterbrochen!");
}

void TCPClient::disco2() {
  ui.progressBar_2->hide();
  ui.label_2->setText("Verbindung mit dem Server unterbrochen!");
}

void TCPClient::disco3() {
  ui.progressBar_3->hide();
  ui.label_3->setText("Verbindung mit dem Server unterbrochen!");
}

void TCPClient::error1(QAbstractSocket::SocketError s_error) {
  ui.progressBar->hide();
  switch (s_error) {
    case QAbstractSocket::ConnectionRefusedError:
      ui.label->setText("Keine Antwort vom Server!");
    break;
    case QAbstractSocket::RemoteHostClosedError:
      ui.label->setText("Der Server hat die Verbindung unterbrochen!");
      break;
    case QAbstractSocket::HostNotFoundError:
      ui.label->setText("Der Server konnte nicht gefunden werden!");
      break;
    default:
      ui.label->setText("fkjghfdkjg");
      break;
  }
}

void TCPClient::error2(QAbstractSocket::SocketError s_error) {
  ui.progressBar_2->hide();
  switch (s_error) {
    case QAbstractSocket::ConnectionRefusedError:
      ui.label_2->setText("Keine Antwort vom Server!");
    break;
    case QAbstractSocket::RemoteHostClosedError:
      ui.label_2->setText("Der Server hat die Verbindung unterbrochen!");
      break;
    case QAbstractSocket::HostNotFoundError:
      ui.label_2->setText("Der Server konnte nicht gefunden werden!");
      break;
  }
}

void TCPClient::error3(QAbstractSocket::SocketError s_error) {
  ui.progressBar_3->hide();
  switch (s_error) {
    case QAbstractSocket::ConnectionRefusedError:
      ui.label_3->setText("Keine Antwort vom Server!");
    break;
    case QAbstractSocket::RemoteHostClosedError:
      ui.label_3->setText("Der Server hat die Verbindung unterbrochen!");
      break;
    case QAbstractSocket::HostNotFoundError:
      ui.label_3->setText("Der Server konnte nicht gefunden werden!");
      break;
  }
}
Laufen beide Prozesse auf einem lokalen Rechner funktioniert alles wunderbar.
Egal ob ich die Prozesse weich beende, oder hart per Taskmanager und Prozess beenden, jedesmal kommen die richtigen Meldungen.

Beim test im Intranet funktioniert dies allerdings nicht mehr. Startet ein Kollege einen TCP Server(nicht mein Serverprogramm) kann ich mich erfolgreich als Client mit diesem verbinden. Fährt er den Server ordnungsgemäß herunter gibt mein Client auch den korrekten zustandswechsel aus.

Zieht er allerdings hart das Kabel passiert nix, der Client merkt nix davon.
Ebenso beim Server. Ich bekomme mit wenn sich der Kollege verbindet, ebenso wen er seinen prozess ordnungsgemäß beendet, aber sobald das Kabel hart gezogen wird ist aus. Keine Änderung vom Status beim Server.
Ich habe locker 1 min gewartet ob da ev noch ein Timeout ablaufen muss, hoffe hat gereicht.
Zuletzt geändert von tamasi am 13. August 2007 09:50, insgesamt 1-mal geändert.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

schau dir mal mit dem ProcessExplorer an, was mit den Sockets passiert.

http://www.microsoft.com/technet/sysint ... lorer.mspx

Die bleiben vermutlich einfach stehen, bis es zu einem Timeout kommt.

Ich schicke über meine Verbindungen immer noch zusätzlich ein Keepalive-Signal in definierten Abständen. Wenn die Antwort auf das Keepalive nicht kommt (oder der Socket abreißt), dann stimmt etwas nicht.

Es wäre ja auch denkbar, dass die Sockets noch stehen, der Kommunikationspartner aber (warum auch immer) nicht mehr in der Lage ist Nachrichten zu verarbeiten, daher fahre ich hier immer zweigleisig.

Ciao,
Sephral
tamasi
Beiträge: 45
Registriert: 5. Juli 2007 15:49

Beitrag von tamasi »

Danke, ich werde es damit einmal probieren.

Mittlerweile testete ich noch etwas und das Problem verschob sich.

Bisher trennten wir die Verbindung jedesmal von dem Rechner des Kollegen. Daher bekam dies sein Server mit, mein Client nicht und umgekehrt.

Jetzt zog ich bei mir den Stecker. Das Ergebnis war genau anders herum jetzt. Mein Programm bekam es mit, der Gegenrechner nicht. Es scheint also ein Problem zu geben, wenn die Verbindung verloren geht, aber der Rechner tzrotzdem noch am Netzwerk angeschlossen ist. In diesem Fall bekommt er nix mit.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wie Sephral werden die Sokcets nicht sofort geschlossen da dies nicht erkannt werden kann. Wenn Du natürlich die Verbindung an deinem Rechner kappst, bekommt das Betriebssystem dies sofort mit (Link down) und die Sockets werden sofort geschlossen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
tamasi
Beiträge: 45
Registriert: 5. Juli 2007 15:49

Beitrag von tamasi »

hmmm

laut den prozessbetrachter ändern sich die sockets nicht, ich warte gerade mal ob irgendwann ein timeout ist, aber glaube ohne eine art "keepalive"-signal wirds wohl nicht gehen. ärgerlich.

vorallem muss man dann einmal testen was mit zwischenzeitlich abgeschickten datenpacketen geschieht nachdem die verbindung wieder hergestellt ist.
Antworten