QTcpSocket - Aborting write and write progress
-
Hey Gurus,
I am writing a Facebook style Messenger app, and I am really happy with its progress so far.
I have come across a couple of problems I can't seem to solve. I have added the ability to send a file between chat rooms and it works very well. My code to send the file is this:
QFile file( fullName ); file.open( QIODevice::ReadOnly); QByteArray l_vDataToBeSent, packedData, fileData; QDataStream l_vStream(&l_vDataToBeSent, QIODevice::WriteOnly); l_vStream.setByteOrder(QDataStream::LittleEndian); unsigned int size = sizeof(messageType) + sizeof(unsigned int) + static_cast<unsigned int>(uuid.length()) + sizeof(unsigned int) + static_cast<unsigned int>(fileName.length()) + sizeof(unsigned int) + static_cast<uint>(file.size()); l_vStream << size; l_vStream << messageType; l_vStream.writeBytes( uuid.toStdString().c_str(), static_cast<unsigned int>(uuid.length())); l_vStream.writeBytes( fileName.toStdString().c_str(), static_cast<unsigned int>(fileName.length())); l_vStream << file.readAll(); prepareDatastream( &l_vDataToBeSent, &packedData ); if ( m_pTcpSocket ) m_pTcpSocket->write(packedData, packedData.length()); file.close();
The prepareDatastream function encrypts the data before it is sent. All data between the clients and server is encrypted in both directions.
My questions are these:
-
If a large file is sent (perhaps >10meg) and the user decides they want to abort the send mid-transfer, is it possible to tell QTcpSocket to abort the current write without disconnecting?
-
Is it possible to get some sort of feedback from QTcpSocket as to the status of the current write so I can display a progress indicator? I have connected a SLOT to the bytesWritten SIGNAL, but it is only ever called the once, and it contains the size of the file being sent, even though the transfer is still in progress. Consequently my progress indicator immediately jumps to 100%. So bytesWritten does not appear to be the answer.
Thanks everyone in advance for your help.
Steve Q. :-)
-
-
You can send data using chunks instead of sending all the data at once. On every write you can check if the user want to stop sending and abort it. On every loop call QApplication::processEvents() to let the ProgressBar paint the progress.
Also you have to connect the signal "disconnected" or maybe "stateChanged" to know if the connection is lost during transferring.
If the user abort the transfer you can send some kind of special message to client to let it know that the transfer is aborted. -
Sending in chuncks is the way to go. Something like:
QFile* file = new QFile( fullName, this ); QTimer* chunkTimer = new QTimer(file); QObject::connect(chunkTimer,&QTimer::timeout,m_pTcpSocket,[=]()->void{ if(!m_keepReading){ //change this boolean to stop sending file->deleteLater(); return; } QByteArray chunck(512,0); const auto actualRead = file.read(chunck.data(),512); m_pTcpSocket->write(chunck); if(actualRead<512) file->deleteLater(); }); chunkTimer.start(0);
P.S.
By looking at your code it would appear you followed a Qt4 tutorial onQTcpSocket
. Since Qt 5.7QDataStream
introduced transactions to simplify the process. See https://wiki.qt.io/WIP-How_to_create_a_simple_chat_application for an updated example that uses transactions.@steveq said in QTcpSocket - Aborting write and write progress:
The prepareDatastream function encrypts the data before it is sent. All data between the clients and server is encrypted in both directions.
Just use
QSslSocket
instead ofQTcpSocket
, there's no need to do it manually -
Maybe also connecting to QTcpSocket::bytesWritten() to do further writing can help here.