PDA

View Full Version : Estimate file transfer code via QTcpSocket



Kempo
18th May 2020, 12:36
Hello.
It was required to do file transfer through QTcpSocket. Googled many different options that confused me.
The first method was done through the transmission of the length of the block and then the block itself. But then I found a more advanced way through transactions, which appeared in Qt 5.7. I did it on it, asynchronously.
Please rate whether it is correctly and how much correctly done? If there are any comments, I will be glad to know them. Thank.

I pass in several variables:
- type of network packet (file, message or other)
If the file is:
- file name
- file size in bytes
- data block
- and at the end a text message

File Transfer Code:


enum PacketType
{
TYPE_NONE = 0,
TYPE_MSG = 1,
TYPE_FILE = 2,
};

void TcpClient::socketSendMessage()
{
QDataStream stream(m_pTcpSocket);
stream.setVersion(QDataStream::Qt_DefaultCompiledV ersion);

stream << PacketType::TYPE_FILE;

QString fileName("/mnt/d/1.png");
QFile file(fileName);
QFileInfo fileInfo(file);
qint64 fileSize = fileInfo.size();

stream << fileName;
stream << fileSize;

int countSend = 0;

if (file.open(QFile::ReadOnly))
{
while(!file.atEnd())
{
QByteArray data = file.read(32768*8);
stream << data;
countSend++;
}
qDebug() << Tools::getTime() << "_CLIENT: ------------------------ countSend FINAL: " << countSend;
}

file.close();

qDebug() << Tools::getTime() << "_CLIENT: send file ok";

QString testStr("TEST_MESSAGE");
stream << testStr;
}

File retrieval code:
Header file server:

#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include "global.h"
#include <QFile>


class MyTcpServer : public QObject
{
Q_OBJECT

public:
explicit MyTcpServer(QObject *parent = nullptr);
~MyTcpServer();

int number;
QString str;

public slots:
void slotNewConnection();
void slotServerRead();
void slotClientDisconnected();
void onSocketReceiveMessage();
void startServer();

private:
QTcpServer * mTcpServer;
QTcpSocket * mTcpSocket;
qint64 sizeReceivedData;
QString fileCopy;
PacketType packetType;

QString filePath;
qint64 fileSize;
QString testStr;
QByteArray tmpBlock;
int countSend;

bool receiveFile(QDataStream &stream);
};

#endif // MYTCPSERVER_H

In the server constructor:

packetType = PacketType::TYPE_NONE;
filePath.clear();
fileSize = 0;
testStr.clear();
sizeReceivedData = 0;
tmpBlock.clear();
countSend = 0;

Message receiving slot:

void MyTcpServer::onSocketReceiveMessage()
{
if (!mTcpSocket || !mTcpSocket->bytesAvailable())
return;

qDebug() << Tools::getTime() << "SERVER: --------------------new-----------------------";
qDebug() << Tools::getTime() << "SERVER: onSocketReceiveMessage: bytesAvailable" << mTcpSocket->bytesAvailable();

QDataStream stream(mTcpSocket);
stream.setVersion(QDataStream::Qt_DefaultCompiledV ersion);

// Getting PacketType
if (packetType == PacketType::TYPE_NONE) {
stream.startTransaction();
stream >> packetType;
if (!stream.commitTransaction()) {
qDebug() << Tools::getTime() << "SERVER: packetType - FAIL commitTransaction";
return;
}
qDebug() << Tools::getTime() << "SERVER: type:" << packetType;
}

if (packetType == PacketType::TYPE_MSG)
{
//
}
else if (packetType == PacketType::TYPE_FILE)
{
//================================================== ==
// Getting filePath

if (filePath.isEmpty()) {
stream.startTransaction();
stream >> filePath;
if (!stream.commitTransaction()) {
qDebug() << Tools::getTime() << "SERVER: filePath - FAIL commitTransaction";
return;
}
qDebug() << Tools::getTime() << "SERVER filePath:" << filePath;
}

//================================================== ==
// Getting fileSize

if (!fileSize) {
stream.startTransaction();
stream >> fileSize;
if (!stream.commitTransaction()) {
qDebug() << Tools::getTime() << "SERVER: fileSize - FAIL commitTransaction";
return;
}
qDebug() << Tools::getTime() << "SERVER: fileSize:" << fileSize;
}

//================================================== ==
// Getting file

if (sizeReceivedData != fileSize)
{
filePath = this->fileCopy; // temp replace file name
QFile file(filePath);
file.open(QFile::Append);

// Work with the file in the loop "while there is data in the socket"
while (!mTcpSocket->atEnd())
{
//================================================== ==
// Getting tmpBlock

stream.startTransaction();
stream >> tmpBlock;

if (!stream.commitTransaction()) {
qDebug() << Tools::getTime() << "SERVER: tmpBlock - FAIL commitTransaction";
break;
}

qint64 toFile = file.write(tmpBlock);

sizeReceivedData += toFile;
countSend++;

tmpBlock.clear();

if (sizeReceivedData == fileSize)
break;

} // while (!mTcpSocket->atEnd())

file.close();

} // if (sizeReceivedData != fileSize)

if (sizeReceivedData != fileSize)
return;

qDebug() << Tools::getTime() << "SERVER: sizeReceivedData END: " << sizeReceivedData;
qDebug() << Tools::getTime() << "SERVER fileSize ORIG:" << fileSize;
qDebug() << "SERVER: countSend FINAL: " << countSend;


//================================================== ==
// Getting testStr

if (testStr.isEmpty()) {
stream.startTransaction();
stream >> testStr;
if (!stream.commitTransaction()) {
qDebug() << Tools::getTime() << "SERVER: testStr - FAIL commitTransaction";
return;
}
qDebug() << Tools::getTime() << "SERVER: testStr:" << testStr;
}

qDebug() << Tools::getTime() << "SERVER: END - bytesAvailable:" << mTcpSocket->bytesAvailable();

// Clear vars
filePath.clear();
fileSize = 0;
tmpBlock.clear();
sizeReceivedData = 0;
testStr.clear();
countSend = 0;

} // else if (packetType == PacketType::TYPE_FILE)
}

Lesiok
18th May 2020, 12:46
First of all : how does the recipient know the length of the file name? One write on the sender side can generate many reads on receiver side and vice versa.

Kempo
18th May 2020, 12:54
First of all : how does the recipient know the length of the file name? One write on the sender side can generate many reads on receiver side and vice versa.
As I understand it, the length of a QString is not transmitted, because Qt itself does this through startTransaction() and commitTransaction(). - https://doc.qt.io/qt-5/qdatastream.html#using-read-transactions
or am I wrong?

Here is just sending a file with a reading block of 10 MB, for 1 time.
Reading is already more than 1 time.

main() 0x7ffeb3ec0fc0
MyTcpServer::startServer() 0x7ffeae040700
TcpClient::startClient() 0x7ffead830700
server is started
ok
"13:45:04.461" _CLIENT: ------------------------ countSend FINAL: 1
"13:45:04.462" _CLIENT: send file ok
CLIENT: "Hello, World!!! I am echo server!\r\n"
"13:45:04.462" SERVER: --------------------new-----------------------
"13:45:04.462" SERVER: onSocketReceiveMessage: bytesAvailable 44
"13:45:04.463" SERVER: type: 2
"13:45:04.463" SERVER filePath: "/mnt/d/1.png"
"13:45:04.464" SERVER: fileSize: 3958548
"13:45:04.464" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.466" SERVER: --------------------new-----------------------
"13:45:04.467" SERVER: onSocketReceiveMessage: bytesAvailable 524292
"13:45:04.468" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.470" SERVER: --------------------new-----------------------
"13:45:04.470" SERVER: onSocketReceiveMessage: bytesAvailable 1048580
"13:45:04.472" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.473" SERVER: --------------------new-----------------------
"13:45:04.473" SERVER: onSocketReceiveMessage: bytesAvailable 1572868
"13:45:04.475" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.476" SERVER: --------------------new-----------------------
"13:45:04.476" SERVER: onSocketReceiveMessage: bytesAvailable 2097156
"13:45:04.479" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.480" SERVER: --------------------new-----------------------
"13:45:04.480" SERVER: onSocketReceiveMessage: bytesAvailable 2621444
"13:45:04.482" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.483" SERVER: --------------------new-----------------------
"13:45:04.483" SERVER: onSocketReceiveMessage: bytesAvailable 3145732
"13:45:04.486" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.487" SERVER: --------------------new-----------------------
"13:45:04.488" SERVER: onSocketReceiveMessage: bytesAvailable 3670020
"13:45:04.490" SERVER: tmpBlock - FAIL commitTransaction
"13:45:04.491" SERVER: --------------------new-----------------------
"13:45:04.491" SERVER: onSocketReceiveMessage: bytesAvailable 3958580
"13:45:04.495" SERVER: sizeReceivedData END: 3958548
"13:45:04.496" SERVER fileSize ORIG: 3958548
SERVER: countSend FINAL: 1
"13:45:04.496" SERVER: testStr: "TEST_MESSAGE"
"13:45:04.497" SERVER: END - bytesAvailable: 0

Lesiok
18th May 2020, 13:38
OK, it is my mistake.