Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Estimate file transfer code via QTcpSocket



  • 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_DefaultCompiledVersion);
    
        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_DefaultCompiledVersion);
    
    	// 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)
    }
    

  • Lifetime Qt Champion

    @vebmaster You should first explain your use case: what are you trying to implement? File transfer over network?



  • A bit overengineeraed if you ask me but it works.
    File transfer doesn't really require processing is just piping raw bytes from one end to the other and you know the file size upfront so you can go use read() and write() on the device directly without using streams but it's not material



  • @jsulm said in Estimate file transfer code via QTcpSocket:

    @vebmaster You should first explain your use case: what are you trying to implement? File transfer over network?

    Yes.

    It was required to do file transfer through QTcpSocket.


Log in to reply