Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Estimate file transfer code via QTcpSocket
Forum Updated to NodeBB v4.3 + New Features

Estimate file transfer code via QTcpSocket

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 3 Posters 383 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    vebmaster
    wrote on last edited by
    #1

    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)
    }
    
    jsulmJ 1 Reply Last reply
    0
    • V vebmaster

      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)
      }
      
      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

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

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      V 1 Reply Last reply
      0
      • VRoninV Offline
        VRoninV Offline
        VRonin
        wrote on last edited by
        #3

        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

        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
        ~Napoleon Bonaparte

        On a crusade to banish setIndexWidget() from the holy land of Qt

        1 Reply Last reply
        3
        • jsulmJ jsulm

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

          V Offline
          V Offline
          vebmaster
          wrote on last edited by
          #4

          @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.

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved