QT QTcpServer::incomingConnection(qintptr handle)

2020-06-25 04:43发布

问题:

I'm trying to create a multithreaded server using Qt for the first time. Normally one would use the socket pointer returned by the QTcpServer::nextPendingConnection() with the socket handle already baked in - but since I'm interfacing with the connecting client on a separate thread, I need to create the socket separately using the qintptr handle from QTcpServer::incomingConnection(qintptr handle). After a very dreary, error-packed debugging session I managed to track down the problem to the QTcpServer::incomingConnection() never being fired?

Has anyone had a similar problem - has something changed over recent versions Qt?

These are the ones I've tried:

  • QTcpServer::incomingConnection(qintptr handle)
  • QTcpServer::incomingConnection(qintptr socketDescriptor)
  • QTcpServer::incomingConnection(int handle)

EDIT:

Creating instance of server:

TestServer *myServer = new TestServer();
myServer->initializeServer(1234);

Which calls:

void TestServer::initializeServer(quint16 port)
{

mainServer = new QTcpServer(this);

mainServer->listen(QHostAddress::Any, port);

qDebug() << "Listening for connections on port: " << port;



}

Server is now listening. When a client connects incomingConnection(qintptr handle) is supposed to be called:

void TestServer::incomingConnection(qintptr socketDescriptor){

TestClient *client = new TestClient(this);
client->setSocket(socketDescriptor);

}

Which calls:

void TestClient::setSocket(quint16 socketDescr)
{
socket = new QTcpSocket(this);

socket->setSocketDescriptor(socketDescr);

connect(socket, SIGNAL(connected()),this,SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this,SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()),this,SLOT(readyRead()));



}

Called on connect() signal:

void TestClient::connected()
{   
qDebug() << "Client connected..."; // This debug never appears in the console, since QTcpServer::incomingConnection isn't being fired.

}

回答1:

You have some errors at your code:

  1. At TestServer your QTcpServer probably aggregated, but you need to inherit it. At this case you try to override incomingConnection() method, but you haven't base class and you just create new incomingConnection(), not override.
  2. You get qintptr descriptor variable from incomingConnection(), but set quint16 type at setSocket() method.
  3. You probably mix client of server and client of your part, which just get incoming connection and handling socket data.

I write some little example below for your understanding tcp client-server communication.

Server part

Main part is server themselves:

#include <QTcpServer>

class TestServer: public QTcpServer
{
public:
    TestServer(QObject *parent = 0);
    void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
};

Just look: I don't aggragate QTcpServer, but inherited it. At this case you can override incomingConnection() method correctly. At constructor we just start server for listening using listen() method:

TestServer::TestServer(QObject *parent):
    QTcpServer(parent)
{
    if (this->listen(QHostAddress::Any, 2323)) {
        qDebug() << "Server start at port: " << this->serverPort();
    } else {
        qDebug() << "Start failure";
    }
}

Then time for overriding incomingConnection():

void TestServer::incomingConnection(qintptr handle)
{
    qDebug() << Q_FUNC_INFO << " new connection";
    SocketThread *socket = new SocketThread(handle);

    connect(socket, SIGNAL(finished()), socket, SLOT(deleteLater()));
    socket->start();
}

I create SocketThread object which handle incoming data:

#include <QThread>
#include <QObject>

class QTcpSocket;

class SocketThread: public QThread
{
    Q_OBJECT
public:
    SocketThread(qintptr descriptor, QObject *parent = 0);
    ~SocketThread();

protected:
    void run() Q_DECL_OVERRIDE;

private slots:
    void onConnected();
    void onReadyRead();
    void onDisconnected();

private:
    QTcpSocket *m_socket;
    qintptr m_descriptor;
};

We inherits from QThread for making our server multithreading, so we have to override run() method:

SocketThread::SocketThread(qintptr descriptor, QObject *parent)
    :  QThread(parent), m_descriptor(descriptor)
{

}

void SocketThread::run()
{
    qDebug() << Q_FUNC_INFO;
    m_socket = new QTcpSocket;
    m_socket->setSocketDescriptor(m_descriptor);

    connect(m_socket, SIGNAL(readyRead()),    this, SLOT(onReadyRead()), Qt::DirectConnection);
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);

    exec();
}

This way we initialize our QTcpSocket, set socket descriptor, connect it with readyRead() and disconnected() signals and start event loop.

void SocketThread::onReadyRead()
{
    QDataStream in(m_socket);
    in.setVersion(QDataStream::Qt_5_5);

    QString message;
    in >> message;
    qDebug() << message;

    m_socket->disconnectFromHost();
}

void SocketThread::onDisconnected()
{
    m_socket->close();
    // Exit event loop
    quit();
}

At onReadyRead() just read some QString from client, write it to console and disconnect from host. At onDisconnected() we close socket connection and exit event loop.

Client part

It is just example and bad-smells style, but i create connection to the server at MainWindow class on QPushButton::clicked signal:

void MainWindow::on_pushButton_clicked()
{
    QTcpSocket *client = new QTcpSocket;
    connect(client, SIGNAL(connected()), this, SLOT(connected()));
    connect(client, SIGNAL(disconnected()), client, SLOT(deleteLater()));

    client->connectToHost(QHostAddress::LocalHost, 2323);
    client->waitForConnected();

    if (client->state() != QAbstractSocket::ConnectedState ) {
        qDebug() << Q_FUNC_INFO << " can't connect to host";
        delete client;
        return;
    }
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_5);
    out << QString("Hello");
    out.device()->seek(0);
    client->write(block);
}

void MainWindow::connected()
{
    qDebug() << Q_FUNC_INFO << " client connected";
}

I create new QTcpSocket, connect it to the signals and try to connect to the host(in my case it is localhost). Wait for connected and check socket status. If all is right I write to socket QString - just example.

It is one of possible ways to organized multithreading client-server architecture, i hope it will be helpfull for you and you find yours bugs.



标签: qt sockets tcp