Russian Qt Forum
Октябрь 02, 2024, 15:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QSslSocket::write [РЕШЕНО]  (Прочитано 3696 раз)
vanchen
Гость
« : Июль 12, 2013, 16:28 »

Приветствую!

Использую Qt 4.7.4.
В потоке крутятся несколько сокетов. Они крайне активно отсылают сообщения в сеть.
Причем, сообщения не большие, но их много.
 Суть в том, что метод QSslSocket::write довольно быстро отъедает память. При закрытии сокета память чистится, но я считаю такое поведение странным. Сомневаюсь, что если я хочу отправить файл в 10гб мне необходимо несколько раз открывать и разрывать соединение для очистки памяти.
Отладка показала что Qt создает много объектов QMetaCallEvent, но далеко не все из них уничтожает. Что посоветуете?
« Последнее редактирование: Июль 16, 2013, 16:54 от vanchen » Записан
alexandros
Гость
« Ответ #1 : Июль 12, 2013, 20:52 »

код в студию
Записан
vanchen
Гость
« Ответ #2 : Июль 15, 2013, 09:41 »

Сервер:
Код:
void MemoryLeakTest::pbStartClicked()
{
TCPServer * serv = new TCPServer();
connect(serv, SIGNAL(newConnection(qint32)), this, SLOT(newClient(qint32)));
if (serv->listen(QHostAddress::Any, 2000))
qDebug()<<"listening";
}

void MemoryLeakTest::newClient(qint32 socketDescriptor)
{
client = new QSslSocket();
connect(client, SIGNAL(readyRead()), this, SLOT(canRead()));
connect(client, SIGNAL(sslErrors(QList<QSslError>)), client, SLOT(ignoreSslErrors()));
client->setSocketDescriptor(socketDescriptor);
client->setPrivateKey("C://defaultKeySpiral.key");
client->setLocalCertificate("C://defaultCertSpiral.crt");
client->startServerEncryption();
qDebug()<<"encrypted "<<(client->waitForEncrypted(3000) ? "true" : client->errorString());
}

void MemoryLeakTest::canRead()
{
client->readAll();
}




Клиент:
Код:
void ThreadClient::run()
{

QSslSocket * client = new QSslSocket();
connect(client, SIGNAL(sslErrors(QList<QSslError>)), client, SLOT(ignoreSslErrors()));
client->connectToHost("127.0.0.1", 2000);
qDebug()<<"Connected "<<client->waitForConnected(3000);
client->setPrivateKey("C://defaultKeyAgent.key");
client->setLocalCertificate("C://defaultCertAgent.crt");
client->startClientEncryption();
if (client->waitForEncrypted(3000))
{
QString mes;
mes.append("sdsds");
for (int i=0;i<500000;++i)
{

client->write(mes.toAscii());
client->waitForBytesWritten(3000);
}
}
else
qDebug()<<client->errorString();

qDebug()<<"finished";
}

Вот тестовый код. Проблема проявляется при установлении защищенного соединения. При отправке сообщений на клиенте растет память. Причем, чем больше сообщений тем больше памяти съедается. Т.е. на размер отъедаемой памяти влияет не размер сообщения а количество отправляемых сообщений.
Записан
alexandros
Гость
« Ответ #3 : Июль 15, 2013, 20:53 »

попробуй очищать

socket->close();
socket->disconnectFromHost();
socket->delteLater()
Записан
vanchen
Гость
« Ответ #4 : Июль 16, 2013, 09:41 »

Если закрывать то все прекрасно очищается. Тут вопросов нету. Вопрос в том: почему растет память во время работы. Если я хочу отправлять очень много сообщений не разрывая соединения то память будет расти.
Записан
vanchen
Гость
« Ответ #5 : Июль 16, 2013, 16:09 »

Разобрался....

Судя по исходникам Qt:
Код:
qint64 QSslSocket::writeData(const char *data, qint64 len)
{
    Q_D(QSslSocket);
#ifdef QSSLSOCKET_DEBUG
    qDebug() << "QSslSocket::writeData(" << (void *)data << ',' << len << ')';
#endif
    if (d->mode == UnencryptedMode && !d->autoStartHandshake)
        return d->plainSocket->write(data, len);

    char *writePtr = d->writeBuffer.reserve(len);
    ::memcpy(writePtr, data, len);

    // make sure we flush to the plain socket's buffer
QMetaObject::invokeMethod(this, "_q_flushWriteBuffer", Qt::QueuedConnection);

    return len;
}

Когда соединение не шифрованное данные уходят сразу на сокет.
Код:
if (d->mode == UnencryptedMode && !d->autoStartHandshake)
        return d->plainSocket->write(data, len);

Но когда соединение шифрованное, вызывается QMetaObject::invokeMethod с параметром  Qt::QueuedConnection.
Событие помещается в очередь и будет обработано только если запущен EventLoop.

Код:
void ThreadClient::run()
{

QSslSocket * client = new QSslSocket();
connect(client, SIGNAL(sslErrors(QList<QSslError>)), client, SLOT(ignoreSslErrors()));
connect(client, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
client->connectToHost("127.0.0.1", 2000);
emit toLog(QString("Connected ") + (client->waitForConnected(3000) ? "true" : "false"));
client->setPrivateKey("C://defaultKeyAgent.key");
client->setLocalCertificate("C://defaultCertAgent.crt");
client->startClientEncryption();
if (client->waitForEncrypted(30000))
{
QString mes;
mes.append("sdsds");
for (int i=0;i<500000;++i)
{

client->write(mes.toAscii());
QCoreApplication::processEvents();
client->waitForBytesWritten(3000);

}
}
else
emit toLog(client->errorString());

emit toLog("finished");
}

Таким образом, добавление в приведенном примере QCoreApplication::processEvents() решает проблему.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.062 секунд. Запросов: 21.