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)
}
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)
}