2013-08-27 7 views
1

Я действительно в тупике и надеюсь, что кто-то там знает что-то о моей проблеме.Зачем удалять объект Qt (QSslSocket), вызывают сбои

У меня есть очень простой клиент и сервер SSL. Соединение прекрасное. Общение прекрасное. Проблема возникает, когда клиент отключается от сервера. Это вызывает сигнал на сервере, который обрабатывается в SLOT error_handler(QAbstractSocket::SocketError in_error). В этой функции я должен представить, что объект sslSocket должен быть удален.

Однако это приводит к сбою в работе сервера. Я не понимаю, что происходит. Я ожидал, что это будет очень просто, но, видимо, мне не хватает какой-то Qt (или другой) концепции.

Может ли кто-нибудь помочь?

код Essential сервер:

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 !!!!!! 
    } 
} 
+1

Вы удаляете объект, который выполняет вызов обработчика ошибок. Это не может быть хорошо. – Mat

+0

Я? Обработчик ошибок является членом «этого», который является объектом SSLServer. Это не то, что я пытаюсь удалить. Объект sslSocket - это то, что я пытаюсь удалить. Он приходит и идет с соединениями. Объект SSLServer присутствует на протяжении всей программы. Не понял ли я что-то в том, что вы говорите? Благодарю. – driftwood

+2

Вы подключили сигнал 'sslSocket' к этому слоту.Эмитентом является тот, кто называет слот (для прямых подключений в любом случае). т. е. как только ваш слот заканчивается, код возвращается обратно в код sslSocket с удаленным «этим». Это очень плохо. – Mat

ответ

1

QSslSocket является QObject. Никогда не удаляйте QObject. Конечно, не делайте этого в слоте. Всегда используйте deleteLater().

4

Использовать QObject::deleteLater() вместо delete с QSslSocket наследует QObject. Вы все равно можете получать сообщения в сокете, которые вызывают сбой, когда вы только delete объекта.

sslSocket->deleteLater(); 

При вызове deleteLater(), Qt автоматически отключает все слоты и сигналы и вызывает объект деструктор после нет никаких отложенных событий доставляется к объекту. См. QObject::~QObject() для получения дополнительной информации.

+0

ОК, я получаю эту часть. Спасибо всем за то, что они вернулись домой. Теперь больше нет сбоев, когда я использую deleteLater. Только часть меня беспокоит, я действительно не знаю, удаляется ли объект с помощью deleteLater(). Правильно ли я это понимаю? Он просто помещает объект в очередь для удаления, но если объект ссылается, он не будет удален. Я предполагаю, что дело в том, что могут быть ссылки на этот объект, который я, возможно, не учитывал, когда я хочу, чтобы объект ушел, и в этом случае объект никогда не удаляется. Таким образом, у меня есть утечка памяти. – driftwood

+0

DeleteLater() является безопасным особенно важным при использовании многопоточных сред, поскольку один поток удаляет какой-либо объект, а затем другой поток посылает сигнал/сообщения удаляемому объекту (неожиданный сенарио, может работать или нет в соответствии с проверкой Qtframework и всеми). – Ashif

+0

@ user2722568 См. Мой обновленный ответ. В нем объясняется, как 'deleteLater()' автоматически отключает все слоты и сигналы и в конечном итоге вызывает деструктор объекта. –

1

Если вы думаете, как можно записать класс QObject, такие как класс SSLSocket, это может быть что-то вроде этого: -

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, а просто пример.

Смежные вопросы