Search code examples
c++qtqtcpsocketqtnetworkqtcpserver

Why client dont connect to server? Qt


Programm works, but client can't connect to the server. (i run 2 examples of programm: client and server). I can't find where is my mistake.

I wrote the codes below.You will see what i want to do if you look at main function.

//main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//выбор клиента или сервера
cout << "1.Client\n2.Server\n";
switch (_getch())
{
case 49: 
    {
    cout<<"client init\n";
    Client* cli = new Client("localhost",1922);

    string line;
    while(line!="exit") {
        cout << "Message : ";
        cin >> line;
        cli->SendData(QString(line.c_str()));
    }
    break;
    }
case 50:
    {
    cout<<"server init\n";
    Server* srv = new Server(0, 1922);
    break;
    }
}

return a.exec();
}

//server.h
class Server : public QTcpServer {
  Q_OBJECT public : Server(QObject *parent = 0, quint16 port = 1922);
  virtual ~Server();

private
slots:
  void acceptConnection();
  void startRead();
  void disconnected();

private:
  QTcpServer *tcpServer;
  QTcpSocket *client;
};

//server.cpp
Server::Server(QObject *parent, quint16 port) : QTcpServer(parent) {
  //tcpServer = new QTcpServer(this);
  connect(this, SIGNAL(newConnection()), this, SLOT(acceptConnection()));

  if (!this->listen(QHostAddress::Any, port))
    std::cout << "unable to start server\n"
              << this->errorString().toUtf8().constData() << endl;
  else
    std::cout << "server started\n";
}

Server::~Server() {
  //delete client;
  close();
}

void Server::acceptConnection() {
  std::cout << "new connection!\n";
  client = nextPendingConnection();

  connect(client, SIGNAL(readyRead()), this, SLOT(startRead()));
  connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));

  qDebug() << "New client from:" << client->peerAddress().toString();
}

void Server::startRead() {
  client = (QTcpSocket *)sender();
  while (client->canReadLine()) {
    QString line = QString::fromUtf8(client->readLine()).trimmed();
    qDebug() << "Client :" << line;

    client->write(QString("Server : I've taken your message (:\n").toUtf8());
  }

}

void Server::disconnected() {

  qDebug() << "Client disconnected:" << client->peerAddress().toString();

  client->write(QString("Server : I wish you didn't leave ):\n").toUtf8());

}

//} <-- EDIT: THIS IS PROBABLY AN EXTRA

//***************************************************************
//client.h
class Client : public QObject {
  Q_OBJECT public : Client(const QString &add, int port, QObject *obj = 0);
  void SendData(QString data);
  virtual ~Client();
  int status();
  QString err;
private
slots:
  void ReadData();
  void slotConnected();
  void slotError(QAbstractSocket::SocketError);

private:
  QTcpSocket *socket;

};

//client.cpp
Client::Client(const QString &add, int port, QObject *obj) : QObject(obj) {
  //create socket
  socket = new QTcpSocket(this);
  //connect
  socket ->connectToHost(add, port);

  connect(socket, SIGNAL(readyRead()), SLOT(ReadData()));
  connect(socket, SIGNAL(connected()), SLOT(slotConnected()));
  connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
          SLOT(slotError(QAbstractSocket::SocketError)));

}

Client::~Client() {
  socket->close();
  delete socket;
}

void Client::SendData(QString data) {
  if (!data.isEmpty()) {
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_1);
    out << quint16(0) << QTime::currentTime() << data;
    out.device()->seek(0);
    out << quint16(arrBlock.size() - sizeof(quint16));

    socket->write(arrBlock);
    socket->flush();
  }
}

void Client::ReadData() {
  QDataStream in(socket);
  in.setVersion(QDataStream::Qt_5_1);
  while (socket->canReadLine()) {

    QString line = QString::fromUtf8(socket->readLine()).trimmed();
    qDebug() << line;
  }
}

void Client::slotConnected() {
  socket->write(QString("Client : Server connection has been made (: \n")
                    .toUtf8());
}

void Client::slotError(QAbstractSocket::SocketError err) {
  QString strError =
      "Error: " + (err == QAbstractSocket::HostNotFoundError
                       ? "The host was not found."
                       : err == QAbstractSocket::RemoteHostClosedError
                       ? "The remote host is closed."
                       : err == QAbstractSocket::ConnectionRefusedError
                       ? "The connection was refused."
                       : QString(socket->errorString()));
  std::cout << strError.toUtf8().constData() << endl;
}

int Client::status() { return socket->state(); }

help me pls!


Solution

  • It's probably becouse of the while loop in main.cpp, it blocks client's event loop, and will return to event loop right after 'exit' will be typed. I mean this lines:

    while (line != "exit") {
      cout << "Message : ";
      cin >> line;
      cli.SendData(QString(line.c_str()));
    }
    

    How this can be avoided: main.cpp MUST reach return a.exec(); line to start event loop (i am excluding some ugly processEvent solutions right away ).

    To send commands to cmd and NOT block event loop i used class i saw somewhere here on stackoverflow:

    example of main.cpp:

    QCoreApplication a(argc, argv);
    qDebug()<<"Press 'q' to quit";
    
    QTcpServer server;
    
    qDebug()<<"Server is started -"<<server.isListening();
    
    // Console reader to filter console input
    ConsoleReader reader;
    QObject::connect(&reader,SIGNAL(shutdown()),&a,SLOT(quit()));
    
    return a.exec();
    

    aaand behold, ConsoleReader class, header:

    #ifndef CONSOLEREADER_H
    #define CONSOLEREADER_H
    
    #pragma once
    
    #include <QObject>
    #include <QSocketNotifier>
    
    class ConsoleReader : public QObject
    {
        Q_OBJECT
    public:
        explicit ConsoleReader(QObject *parent = 0);
        ~ConsoleReader();
    signals:
        void shutdown();
    public slots:
        void text();
    private:
        QSocketNotifier* notifier;
    };
    
    #endif // CONSOLEREADER_H
    

    source:

    #include "consolereader.h"
    #include <QTextStream>
    #include <QDebug>
    #include <unistd.h> //Provides STDIN_FILENO
    
    ConsoleReader::ConsoleReader(QObject *parent) :
        QObject(parent)
    {
        notifier = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read);
        connect(notifier, SIGNAL(activated(int)), this, SLOT(text()));
    }
    
    void ConsoleReader::text()
    {
        QTextStream qin(stdin);
        QString line = qin.readLine();
        if (line==QString("q")){
            qDebug()<<"Shutting down the server..";
            emit shutdown();
        }
        else qDebug()<<"Unknown command: "<<line;
    
    }
    
    ConsoleReader::~ConsoleReader(){
        delete notifier;
    }