Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTcpServer::newConnection() does not work when realized in another class



  • As title, my purpose is open the listen and when a new connection is coming, do something.
    I don't want to write all my functions in the mainwindow, so I create another class to realize this function.
    as my coding follow, I used the first kind of init(), but it does not work, I try in the second init(), it works.

    I want to know why can you tell me? this is part codes in my 2 files.

    mainwindow.cpp

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->label->setText("Disconnected!");
    
        ui->pushButton_send->setEnabled(false);
    
        bool isInitialized;
    
        // the first kind of init to open listen and get connection, init() is in another class called Server
        Server server;
        isInitialized = server.init();
    
        // the second method to open listen and get connection, init() is in the same class
        isInitialized = init();
    
        qDebug()<<isInitialized;
    }
    
    int MainWindow::init()
    {
        server = new QTcpServer();
        connect(server, SIGNAL(newConnection()), this, SLOT(server_New_Connect()));
        int port = 5007;
        if(!server->listen(QHostAddress::Any,port))
        {
            ui->label_listen->setText("fail to listen");
            qDebug()<<server->errorString();
            return 0;
        }
    
        ui->label_listen->setText("listen succeed");
        return 1;
    }
    

    Server.cpp

    bool Server::init()
    {
        bool isInitialized = listen(QHostAddress(SERVER_IP), SERVER_PORT);
        if (isInitialized)
        {
            m_serverStatus = SERVER_STATUS_OK;
            QThreadPool::globalInstance()->setMaxThreadCount(QTNConst::NUM_MAX_CLIENTS);
            connect(this, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
        }
        return isInitialized;
    }
    


  • @gaosiy
    it's very confused...
    Why are you trying to create 2 QTcpServer (maybe in same port) ? i suppose that Server Class is a derived from QTcpServer



  • thanks for replay
    when I use this code, I will use just one of these.
    I show all of them cause it will be clear.



  • @gaosiy
    I tested an similiar example:

    void Server::init()
    {
        bool isListening = listen(QHostAddress("127.0.0.1"), 5007);
    
        if(isListening){
            qDebug() << "IS LISTENING";
            connect(this, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
        }
    }
    
    void Server::onNewConnection()
    {
        qDebug() << "Incoming Connection";
    }
    

    The newConnection signal is invoking onNewConnection normaly.

    Note: If your class should use signal and slot feature, you need to define Q_OBJECT macro.

    class Server : public QTcpServer{
       Q_OBJECT
       // your derivered class implementation
    public:
       Server();
    };
    


  • @KillerSmath said in QTcpServer::newConnection() does not work when realized in another class:

    Q_OBJECT

    thanks again!
    I can also work it when test in a console application.
    but in mainwindow (with ui), it does not work.



  • @gaosiy
    What exactly do you pretent to change or access on mainwindow ?

    You can capture the Server newConnection Signal and invoke a MainWindow slots as onNewConnectionServer()

    /////
    //h file
    /////
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    private slots:
        void onNewConnectionServer();
    private:
        Ui::MainWindow *ui;
        Server server;
    };
    ////
    // cpp file
    //////
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        connect(&server, SIGNAL(newConnection()), this, SLOT(onNewConnectionServer()));
        server.init();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::onNewConnectionServer()
    {
        // acess ui
    }
    


  • @KillerSmath said in QTcpServer::newConnection() does not work when realized in another class:

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

    connect(&server, SIGNAL(newConnection()), this, SLOT(onNewConnectionServer()));
    server.init();
    

    }

    thanks!
    in this code, can the nowconnection in the connect work if you put it in init() in another class?
    I know it can work if I put it in the constructor directly



  • @gaosiy
    You can... but it is strange idea...

    2 Ways to achieve it:

    1. Storage a pointer to MainWindow object
    2. Pass MainWindow as Parent of Server Object

    Example of how you could implement it by Parent Method:

    MainWindow::MainWindow()
    {
    ...
    Server *server = new Server(this);
    server->init();
    ...
    }
    

    Change Server construtor to receive QObject pointer

    class Server : public QTcpServer
    {
        Q_OBJECT
    public:
        Server(QObject *parent);
        ~Server();
    
        void init();
    };
    

    Call QTcpServer Construtor (Base Class) passing parent

    Server::Server(QObject *parent) : QTcpServer(parent) // call QTcpServer construtor
    {
    
    }
    

    Cast the parent to MainWindow (parent) and create the connection

    void Server::init()
    {
        bool isListening = listen(QHostAddress("127.0.0.1"), 5007);
    
        if(isListening){
            MainWindow *window = qobject_cast<MainWindow*>(parent());
            connect(this, SIGNAL(newConnection()), window, SLOT(onNewConnectionServer()));
        }
    }
    

    But why necessarily do you need to create the connection inside of Init function ?



  • @KillerSmath

    thanks.
    I can show you why i want to achieve it at the other class.
    this file is my first version of tcp communication without any UI

    //QTNetworkDemo.cpp
    #include "QTNetworkDemo.h"
    #include "client/QTNClient.h"
    #include "server/QTNServer.h"
    #include <QTNConst.h>
    
    QTNetworkDemo::QTNetworkDemo(int argc, char *argv[])
    : QCoreApplication(argc, argv),
    CLIENT_CHOICE_STR(QTNConst::CLIENT_CHOICE_STR),
    SERVER_CHOICE_STR(QTNConst::SERVER_CHOICE_STR),
    EXIT_CHOICE_STR(QTNConst::EXIT_CHOICE_STR),
    m_opCode(OP_CODE_ERROR)
    {
    
    }
    
    int QTNetworkDemo::exec()
    {
        bool isInitialized;
    
        QTNServer server;
    
        qDebug()<<"1"<<endl;
    
        isInitialized = server.init();
    
        return QCoreApplication::exec();
    }
    
    int main(int argc, char *argv[])
    {
        QTNetworkDemo demo(argc, argv);
    
        return demo.exec();
    }
    
    

    and this is server.cpp

    //  QTNServer.cpp
    
    #include "QTNServer.h"
    #include "QTNServerThread.h"
    #include <QTNConst.h>
    #include <QTcpSocket>
    #include <QStringList>
    #include <QTimer>
    #include <QThreadPool>
    
    QTNServer::QTNServer()
    : SERVER_IP(QTNConst::SERVER_IP),
    SERVER_PORT(QTNConst::SERVER_PORT),
    m_serverStatus(SERVER_STATUS_IDLE),
    m_numMaxClients(QTNConst::NUM_MAX_CLIENTS)
    {
    
    }
    
    bool QTNServer::init()
    {
        std::cout << getStatusDescription().c_str() << "is initializing " << "ip: " << SERVER_IP << ", port: " << SERVER_PORT << "\n";
    
        bool isInitialized = listen(QHostAddress(SERVER_IP), SERVER_PORT);
        if (isInitialized)
        {
            m_serverStatus = SERVER_STATUS_OK;
            std::cout << getStatusDescription().c_str() << "is listening\n";
            QThreadPool::globalInstance()->setMaxThreadCount(QTNConst::NUM_MAX_CLIENTS);
            connect(this, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
            QTimer::singleShot(1000, this, SLOT(printClients()));
        }
        else
        {
            m_serverStatus = SERVER_STATUS_NOK;
            std::cout << getStatusDescription().c_str() << "is NOT listening\n";
        }
    
        return isInitialized;
    }
    

    when I use the first version, it works well.
    but when I want to use TCP communication with UI, the same way of my method does not work
    so I fell very strange and I can't understand why...



  • @KillerSmath

    And I find when I do like this in exec()

    //return QCoreApplication::exec();
    

    it does not work as the UI version.
    I dont know why.


  • Qt Champions 2019

    @gaosiy said in QTcpServer::newConnection() does not work when realized in another class:

    but when I want to use TCP communication with UI, the same way of my method does not work

    You should not do it same way in a UI application: your UI application will already have an event loop.
    Doing the connect in MainWindow constructor (or its init() method) is perfectly valid and the right thing to do. Your server should not know anything about your UI, so it can't do the connect to UI as it does not know anything about it :-)


Log in to reply