为什么删除Qt(QSslSocket)对象会导致崩溃

时间:2013-08-27 17:37:46

标签: c++ qt

我真的很难过,希望有人知道我的问题。

我有一个非常简单的SSL客户端和服务器。连接很好。沟通很好。当客户端与服务器断开连接时,会出现问题。这会在服务器上触发一个信号,该信号在SLOT error_handler(QAbstractSocket::SocketError in_error)中处理。在那个函数中,必须删除sslSocket对象,我想。

但是这样做会导致服务器出错。我不明白发生了什么。我希望这很简单,但显然我缺少一些Qt(或其他)概念。

有人可以帮忙吗?

基本服务器代码:

void SSLServer::incomingConnection(int sd)
{
    sslSocket = new SSLSocket(this);
    if( sslSocket->setSocketDescriptor(sd))
    {
        QFile sslkeyfile(privKey_);
        sslSocket->setPrivateKey(QSslKey(sslkeyfile.readAll(),QSsl::Rsa));

        QFile cliCertFile(serverCert_);
        sslSocket->setLocalCertificate(QSslCertificate(cliCertFile.readAll()));

        QFile certFile(caCert_);
        sslSocket->addCaCertificate(QSslCertificate(certFile.readAll()));

        sslSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
        sslSocket->setProtocol(QSsl::SslV3);

        connect(sslSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                this, SLOT(error_handler(QAbstractSocket::SocketError)));
        connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
                this, SLOT(ssl_error_handler(QList<QSslError>)));
        connect(sslSocket, SIGNAL(encrypted()), this,
                SLOT(ready()));
        connect(sslSocket, SIGNAL(readyRead()), this,
                SLOT(read_data_from_client()));

        sslSocket->startServerEncryption();
        if(!sslSocket->waitForEncrypted())
        {
            qDebug() << "failed to perform SSL handshake with client";
            return;
        }
    }

}

void SSLServer::read_data_from_client()
{
    QByteArray qstrbytes = sslSocket->readAll();
    qDebug() << Q_FUNC_INFO << qstrbytes;
}

void SSLServer::ready()
{
    QSslCertificate clientCert = sslSocket->peerCertificate();
    qDebug() << clientCert.isValid();
}

void SSLServer::error_handler(QAbstractSocket::SocketError in_error)
{
    qDebug() << Q_FUNC_INFO << in_error;
    if(in_error == QAbstractSocket::RemoteHostClosedError)
    {
        delete sslSocket; //// line causes crash !!!!!!
    }
}

4 个答案:

答案 0 :(得分:5)

使用QObject::deleteLater()代替delete,因为QSslSocket会继承QObject。当您只是delete对象时,您仍可能在套接字上收到导致崩溃的消息。

sslSocket->deleteLater();

当您调用deleteLater()时,Qt会自动断开所有插槽和信号,并在没有挂起事件传递给对象后调用对象析构函数。有关详细信息,请参阅QObject::~QObject()

答案 1 :(得分:2)

如果您认为可以编写诸如SSLSocket类之类的QObject类,它可能是这样的: -

class SSLSocket : public QObject
{        
   signals:
        void sslErrors(QList<QSslError>);

     void SomeFunction()
     {
        // something went wrong, emit error
        emit sslErrors(errorList);

        Cleanup(); // If a slot connected to sslErrors deleted this, what happens now?!
     }
}

当触发信号sslErrors时,将调用您的插槽功能。如您所见,在发出信号后,班级可能还有更多工作要做。如果你立即删除了插槽中的对象,这将会崩溃,这就是为什么你应该总是使用deleteLater()来删除插槽函数中的QObject实例。

deleteLater函数将确保插槽函数已完成执行并恢复调用堆栈,因此将在适当的时候删除它。

请注意,上面的代码实际上并不是SSLSocket所做的,而只是一个例子。

答案 2 :(得分:1)

QSslSocket是一个QObject。永远不要只删除QObject。当然不要在插槽中这样做。始终使用deleteLater()。

答案 3 :(得分:1)

这是使用QSslSocket的Qt示例代码:

http://qt-project.org/doc/qt-4.8/network-securesocketclient-sslclient-cpp.html

正如其他海报提到的那样,使用deleteLater(),错误通知不是唯一可以这样做的地方。