Data / file transfer via TCP



  • Hey there,

    I want to realize a data/file transfer between 2 classes, one client and one server. I allready get an connection using the QT Classes "QTcpServer" "QTcpSocket". And I can send messages using this:

    //code here
    void Server::sendString()  {
    	// send via QByteArray 
    	QByteArray block;
    	QDataStream out(&block, QIODevice::WriteOnly);
    	out.setVersion(QDataStream::Qt_5_5);
    	out << (quint16)0;
    	// create data for the client 
    	QString data;
    	data.append(tr("Just some bla "));
    	out << data;
    	out.device()->seek(0);
    	out << (quint16)(block.size() - sizeof(quint16));
    	// get the next client-connection
    	QTcpSocket *clientConnection =
    		tcpServer->nextPendingConnection();
    	// signal  
    	connect(clientConnection, SIGNAL(disconnected()),
    		clientConnection, SLOT(deleteLater()));
    	// write the string into the socket
    	clientConnection->write(block);
    	// disconnect
    	clientConnection->disconnectFromHost();
    }
    

    now I want to send files. I tried it using class "QFile", but I failed.
    Is my approach right?? How would you do a data/file transfer via TCP?

    thank you for your help.

    greetings
    Thomas


  • Qt Champions 2016

    hi
    It seems fine. If you can send the QString Data, you can send anything you like.
    If you want to send a binary file, then you should never ever convert to string or char *
    as you will only get up till first 0 (zero) it finds.
    so to send say an image: (pseudo code-ish)

    QFile file("c:/mypic.jpg");
    file.open(QIODevice::ReadOnly);
    QByteArray mydata=file.readAll();
    then then clientConnection->write(mydata).
    

    On the receiver end, also read it as QByteArray and
    save to file again.

    QByteArray data;
    // read ...
    QFile file("C:/path/myimage.jpg"); // change path
    file.open(QIODevice::WriteOnly);
    file.write(data);
    file.close();
    


  • Hi,
    thank you for your help!!
    I tried to implement it, with your advice, but my program just create an empty file.
    There could be a problem with my server class, because I did't understand how I get the bytes in a DataStream.
    I thouht the command file.readAll() reads the whole file and QDataStream puts this into my Socket.
    But now I think it isn't that easy!??

    In my Server Class

    void Server::sendData()  {
    	QFile file("C:/Uploads/test.zip");
    	if (!file.open(QFile::ReadOnly))
    	{
    	ui.label_Server_Status_Header ->setText(
          tr("Could not open the file for reading"));
    		return;
    	}
    	QByteArray mydata = file.readAll();
    	QDataStream out(&mydata, QIODevice::WriteOnly);
    
        out.setVersion(QDataStream::Qt_5_5);
    	out.device()->seek(0); // sets device
    	//out << (quint64) mydata.size();
    	//out << (quint16)0;
    	out << (quint64) mydata.size();  // filesize // mydata or file.size() ???
    	out << mydata;
    
        // get the next client-connection
        QTcpSocket *clientConnection =
            tcpServer->nextPendingConnection();
        // signal  
        connect(clientConnection, SIGNAL(disconnected()),
            clientConnection, SLOT(deleteLater()));
        // write the string into the socket
        clientConnection->write(mydata);
        // disconnect
        clientConnection->disconnectFromHost();
    }
    

    In my Client Class

    // read Servers datas
    void Client::readData() {
    QDataStream in(tcpSocket);
    	in.setVersion(QDataStream::Qt_5_5);
      
    	if (blockSize == 0) {     
    		// data to read available   
    		if ( tcpSocket->bytesAvailable() <         
    			(int)sizeof(quint16) )        
    			return;     
    		in >> blockSize; 
    	} 
    	if (tcpSocket->bytesAvailable() < blockSize)    
    		return;
    
    	QByteArray nextByte;
    	// read ...
    	in >> nextByte;
    	
    	/*if (nextByte == currentByte) {
         QTimer::singleShot(0, this, SLOT(requestNewConnection()));
         return; 
    	}*/
    
    	currentByte = nextByte;
    	QFile file("C:/Downloads/test.zip"); // download path
    	file.open(QIODevice::WriteOnly);
    	file.write(currentByte);
    	file.close();
     
      ui.getTimeButton->setEnabled(true);
    }
    
    

  • Qt Champions 2016

    Hi
    you must use the debugger to find out what went wrong.
    you write the size of the zip file as a header.

    Do you get the size over correctly ?
    Meaning that blockSize is actually mydata.size();
    also after
    in >> nextByte;
    if you
    qDebug() << "bytes read: " << nextByte.size();

    what you get as output?



  • Hi,

    what do you do in server is

    socket->write(data);
    socket->disconnectFromHost();
    

    IMO is not correct because you should wait that the bytes are written before closing the connection for instance

    socket->write(data);
    // Wait until data are written to the native socket buffer
    socket->waitForBytesWritten();
    socket->disconnectFromHost();
    

  • Lifetime Qt Champion

    Hi,

    One other thing:
    You are creating your QDataStream on your file buffer, then you write the block size in place of the first bytes of your file.

    Taking the fortune server examples code, it should be:

    QByteArray block; // Data that will be sent
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_5);
    out << (quint64)0; // Space for size of data
    out << file.readAll(); // Actual data
    out.device()->seek(0);
    out << (quint64)(block.size() - sizeof(quint64));
    

  • Qt Champions 2016

    @Jeff_T69
    Hello,

    This part:

        QByteArray mydata = file.readAll();
        QDataStream out(&mydata, QIODevice::WriteOnly);
    
        out.setVersion(QDataStream::Qt_5_5);
        out.device()->seek(0); // sets device
        //out << (quint64) mydata.size();
        //out << (quint16)0;
        out << (quint64) mydata.size();  // filesize // mydata or file.size() ???
        out << mydata;
    

    looks very suspicious. I don't get it. You read the file, then create a data stream attached to the buffer containing the file and then write it over with the << operator? What exactly is it that this part of the code is trying to achieve?
    I believe simply doing this is sufficient:

    QTcpSocket * socket = tcpServer->nextPendingConnection();
    socket->write(mydata);
    if (!socket->waitForBytesWritten())
         ; // Some error occured
    socket->disconnectFromHost();
    

    Similarly on the client side:

    if (tcpSocket->bytesAvailable() <= 0)
        return;
    
    while (tcpSocket->state() == QAbstractSocket::ConnectedState)  {
        tcpSocket->waitForReadyRead();
        file.write(tcpSocket->read(tcpSocket->bytesAvailable()));
    }
    

    Additionally, don't open the file at every read, just open it once and then write. The way you're doing it, the file contents will always be overwritten on each subsequent call.

    Kind regards.

    EDIT:
    It seems @SGaist beat me to it and posted while I was writing. I see now what the idea of the first part of the code is.



  • Thank you very much for all your replies. I see what went wrong.
    Now it works very well.

    Server Class

    void Server::sendData()  {
    	QFile file("C:/Uploads/Test.zip");
    	
    	if (!file.open(QFile::ReadOnly))
    	{
    	ui.label_Server_Status_Header ->setText(
          tr("Could not open the file for reading"));
    		return;
    	}
    
    	QByteArray block; // Data that will be sent
    	QDataStream out(&block, QIODevice::WriteOnly);
    	out.setVersion(QDataStream::Qt_5_5);
    	out << (quint64)0; // Space for size of data
    	out << file.readAll(); // Actual data
    	out.device()->seek(0);
    	out << (quint64)(block.size() - sizeof(quint64));
    
        // get the next client-connection
        QTcpSocket *clientConnection =
            tcpServer->nextPendingConnection();
        // signal  
        connect(clientConnection, SIGNAL(disconnected()),
            clientConnection, SLOT(deleteLater()));
        // write the string into the socket
        clientConnection->write(block);
    	// Wait until data are written to the native socket buffer
    	clientConnection->waitForBytesWritten();
        // disconnect
        clientConnection->disconnectFromHost();
    }
    

    Client Class

    // read Servers datas
    void Client::readData() {
    QDataStream in(tcpSocket);
    	in.setVersion(QDataStream::Qt_5_5);
      
    	if (blockSize == 0) {     
    		// data to read available   
    		if ( tcpSocket->bytesAvailable() <         
    			(int)sizeof(quint16) )        
    			return;     
    		in >> blockSize; 
    	} 
    	if (tcpSocket->bytesAvailable() < blockSize)    
    		return;
    
    	QByteArray nextByte;
    	// read
    	in >> nextByte;
    
    	currentByte = nextByte;
    	QFile file("C:/Downloads/Test.zip"); // download path
    	
    	file.open(QIODevice::WriteOnly);
    	file.write(currentByte);
    	file.close();
     
      ui.getTimeButton->setEnabled(true);
    }
    


  • hi all,
    If file size is 1000 kb it is possible to send all the data



  • @karti-gesar yes, of course



  • @VRonin

    QFile file("D:/serial_Data.txt");
        file.open(QIODevice::ReadOnly);
        QByteArray mydata=file.readAll();
         socket->write(mydata);
    //Serial_Data file size is 1072kb but only 1 kb is writting
    


  • add socket->waitForBytesWritten(-1);

    P.S.
    Since your file is a text file probably what you are reading is not what you want and/or it's not solid to change. you should use:

    QFile file("D:/serial_Data.txt");
    if(file.open(QIODevice::ReadOnly | QIODevice::Text)){
    const auto mydata=QTextStream(&file).readAll();
    QDataStream socketStream(socket);
    socketStream << mydata;
    socket->waitForBytesWritten(-1);
    }
    


  • k i will try



  • QFile file("D:/serial_Data.txt");
     if(file.open(QIODevice::ReadOnly| QIODevice::Text))
       {
            const auto mydata=QTextStream(&file).readAll();
           QDataStream socketStream(socket);
           socketStream << mydata;
           socket->waitForBytesWritten(-1);
         qDebug()<<mydata.constData();
       }
    

    this what i used....for file size smaller it's working ..for huge file size it not writing



  • @karti-gesar said in data/ file transfer via TCP:

    huge

    You should define huge but in this case you can use:

    QFile file("D:/serial_Data.txt");
    if(file.open(QIODevice::ReadOnly | QIODevice::Text)){
    QDataStream socketStream(socket);
    QTextStream fileStream(&file);
    for(QString mydata=fileStream.readLine();!mydata.isEmpty();mydata=fileStream.readLine())
    socketStream << mydata;
    socket->waitForBytesWritten(-1);
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.