Problem with IMAP and QTcpSocket
Hello, I am writing an Imap client but I need Your help to improve my code, I have tried to solve it, but I don't know how. I guess it is some problem with too big data stored in QByteArray
As first my program generates very hight CPU usage when I try download using Imap, it is 100% of my Core i7. I am sure it is some bug in download function because as normal does not exceed 10%
Second problem I found is that download speed slows down about 10kb/s and finish on few bytes/s making my client unusable, (can't download bigger file than 3mb)
Imap.cpp (download function)
Code:
void Imap
::downloadFile(int message_id,
QString filename
){ m_logger->Debug("IMAP - downloading: " + this->m_login);
this->login();
sendCommand("a03 EXAMINE INBOX", "a03");
m_dowloadFile = true;
qint64 size = 0;
for(int i = 0; i < m_mailData.count(); i++){
if(m_mailData[i].messageId == message_id){
size = m_mailData[i].size;
}
}
this->getProgressListener()->startTimer();
this->getProgressListener()->setTotal(size);
m_file
= new QFile(filename
);
sendCommand
("a09" + QString::number(message_id
) + " fetch " + QString::number(message_id
) + " BODY.PEEK[2]",
"a09" + QString::number(message_id
));
m_file->close();
} else {
m_statusCode = Mailbox::FileWriteError;
}
this->disconectFromHost();
delete m_file;
m_file = NULL;
m_dowloadFile = false;
}
Part of SocketsBase.cpp
Code:
ocketsBase
::SocketsBase(QString server,
int port,
bool ssl_mode, EConnectionType type,
QObject *parent
) :{
m_server = server;
m_port = port;
m_SSLMode = ssl_mode;
m_logger = Logger::getInstance();
m_connectionType = type;
m_file = NULL;
m_dowloadFile = false;
m_finished = false;
m_running = false;
m_Sockets
= (m_SSLMode
) ?
new QSslSocket
(this) : new QTcpSocket(this);
connect(m_Sockets, &QAbstractSocket::readChannelFinished, [=]()
{
emit finished();
});
connect(m_Sockets, SIGNAL(readyRead()), this, SLOT(ready_read()), Qt::DirectConnection);
connect(m_Sockets, SIGNAL(connected()), this, SLOT(connected()));
m_success = true;
}
void SocketsBase::ready_read()
{
m_finished = false;
connect(m_timer, &QTimer::timeout, [=]() {
emit timeOutReached();
});
m_timer->start(240000);
if(m_dowloadFile)
{
ProgressListener::getInstance(m_login)->updateProgress(ProgressListener::getInstance(m_login)->getCurrent() + m_Sockets->bytesAvailable());
m_logger
->Debug
(trUtf8
("Bytes available %s"), qPrintable
(QString::number(m_Sockets
->bytesAvailable
())));
}
while(!m_Sockets->atEnd()){
if(m_Sockets->bytesAvailable() > 4096){
m_dataBuffer.append(m_Sockets->read(4096));
}else{
m_dataBuffer.append(m_Sockets->readAll());
}
}
m_Sockets->flush();
m_logger
->Error
(QString::number(m_dataBuffer.
size()));
QRegExp re
(".[\r][?\n]?a[0-9]+ OK Success.*");
QRegExp re2
(".[\r]?[\n]?a[0-9]+ OK [fetchFETCH]+.*");
if(((re1.indexIn(m_dataBuffer) != -1 && !m_dowloadFile) || (m_dowloadFile && re.indexIn(m_dataBuffer) != -1) )|| re2.indexIn(m_dataBuffer) != -1 || m_currentCode == "-1" || m_connectionType == POP3)
{
if(m_dowloadFile)
{
if(m_file)
{
if(!m_file->isOpen())
{
m_logger->Error(trUtf8("Couldn't open file %s to write"), qPrintable(m_file->fileName()));
}
out << m_dataBuffer;
//...
}
}
m_timer->stop();
emit finished();
}
//
//...
//...
//
else if(m_dataBuffer.contains("NULL") || m_dataBuffer.contains("null")){
m_logger->Error("Buffer is null !");
m_dataBuffer.clear();
emit finished();
}
}
m_dataBuffer is QByteArray
Any suggestions ?
Re: Problem with IMAP and QTcpSocket
This is very important for me, please give me some suggestions. Do You need more code ? Better description or additional informations ?
Cheers
Re: Problem with IMAP and QTcpSocket
Some observations:
1) you send the fetch command and immediately after close the file
2) you then disconnect and delete the file
so how does that even get any data?
Smells like nested event loop but cold even be as worse as busy-looping
3) in your ready_read slot you locally create the regular expressions every time?
4) you parse the buffer every time?
5) if m_dataBuffer is a QByteArray, why write it with a QTextStream?
6) you use a lambda to emit finished() when the socket emits readChannelFinished, that cane done way simpler with a signal/signal connection
Cheers,
_
Re: Problem with IMAP and QTcpSocket
Thank You ! :) It works really good after Your suggestions