【问题标题】:Why would deleting a Qt (QSslSocket) object cause a crash为什么删除 Qt (QSslSocket) 对象会导致崩溃
【发布时间】:2013-08-28 18:01:12
【问题描述】:

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

我有一个非常简单的 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 !!!!!!
    }
}

【问题讨论】:

  • 您正在删除正在调用错误处理程序的对象。这可不好。
  • 我是??错误处理程序是“this”的成员,它是 SSLServer 对象。那不是我要删除的内容。 sslSocket 对象是我要删除的对象。它伴随着联系来来去去。 SSLServer 对象在程序期间存在。我是不是误解了你所说的某些内容?谢谢。
  • 您已将sslSocket 的信号连接到该插槽。发射器是调用插槽的人(无论如何都是直接连接)。即,一旦您的插槽完成,代码会流回 sslSocket 代码中的某个位置,并删除 this。这很糟糕。
  • 啊,我认为这是有道理的。谢谢。我将相应地修改我的代码,看看它在哪里。如果我发现有用的东西,请告诉你。

标签: c++ qt


【解决方案1】:

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

sslSocket->deleteLater();

当您调用deleteLater() 时,Qt 会自动断开所有槽和信号,并在没有未决事件传递给对象后调用对象析构函数。请参阅QObject::~QObject() 了解更多信息。

【讨论】:

  • 好的,我明白了。感谢大家把重点带回家。现在我正在使用 deleteLater,不再崩溃。唯一困扰我的部分是我真的不知道该对象是否曾经被 deleteLater() 删除。我理解正确吗?它只是将对象放入队列中以供删除,但如果正在引用该对象,则它不会被删除。我想关键是可能有对那个对象的引用,当我的意思是让对象消失时,我可能没有考虑到,在这种情况下,对象永远不会被删除。因此我有内存泄漏。
  • DeleteLater() 在使用多线程环境时特别重要,因为一个线程删除了某个对象,然后另一个线程向已删除的对象发送信号/消息(意外的情况,根据 Qtframework 验证和所有)。
  • @user2722568 请查看我的更新答案。它解释了deleteLater() 如何自动断开所有槽和信号并最终调用对象析构函数。
【解决方案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 被触发时,你的 slot 函数被调用。如您所见,发出信号后,该类可能还有更多工作要做。如果你立即删除槽中的对象,这将会崩溃,这就是为什么你应该始终使用 deleteLater() 来删除槽函数中的 QObject 实例。

deleteLater函数会保证slot函数执行完毕,调用栈恢复,所以会在适当的时候被删除。

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

【讨论】:

    【解决方案3】:

    QSslSocket 是一个 QObject。永远不要只删除一个 QObject。当然不要在插槽中执行此操作。始终使用 deleteLater()。

    【讨论】:

      【解决方案4】:

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

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

      正如其他发帖者提到的,使用deleteLater(),错误通知并不是唯一这样做的地方。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-28
        • 1970-01-01
        • 1970-01-01
        • 2015-10-22
        • 1970-01-01
        • 1970-01-01
        • 2012-01-05
        相关资源
        最近更新 更多