Results 1 to 14 of 14

Thread: File transfer through sockets

  1. #1
    Join Date
    May 2010
    Posts
    19
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default File transfer through sockets

    I want to send a large file using qt's socket programming for this is edited the existing fortune client-server code as follows:

    Server code:-

    void Server::SendData()
    {
    QByteArray block;
    QByteArray data;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
    while(1)
    {
    out << quint64(0);
    data = inputFile.read(32768*8);
    qDebug() << "Read : " << data.size();
    if(data.size()==0)
    break;
    out << data;
    out.device()->seek(0);
    out << quint64(block.size() - sizeof(quint64));
    client.write(block);
    qDebug() << "Written : " << block.size();
    //block.clear();
    }
    client.disconnectFromHost();
    client.waitForDisconnected();
    }

    Client Code:-

    void Client::ReadData()
    {
    QFile file(filename);
    if(!(file.open(QIODevice::Append)))
    {
    qDebug("File cannot be opened.");
    exit(0);
    }

    QDataStream in(client);
    QByteArray data;
    in.setVersion(QDataStream::Qt_4_0);


    if (blockSize == 0) {
    if (client->bytesAvailable() < sizeof(quint64))
    return;
    in >> blockSize;
    }

    if (client->bytesAvailable() < blockSize)
    return;

    data = client->readAll();
    file.write(data);
    qDebug() << "Written : " << data.size() ;
    blockSize = 0;
    file.close();
    }

    So according to documentation whenever data is available on socket the readyRead() signal is emitted, i have connected Slot ReadData() to it.
    The problem is full file is not transferred on the client side ,lot of data is missing(tested 1.3 G, only 1.2 G was received)
    Can any one please tell what is wrong in the above code?

  2. #2
    Join Date
    Mar 2012
    Location
    Tver, Russia
    Posts
    9
    Thanks
    1
    Thanked 3 Times in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: File transfer through sockets

    May server transfer blocks with length less than client expects? I can be mistaken, but last block will not be saved.
    Qt Code:
    1. if (client->bytesAvailable() < blockSize)
    2. return;
    To copy to clipboard, switch view to plain text mode 
    Try to find block on which transferring stops and check client's behaviour.

  3. #3
    Join Date
    May 2010
    Posts
    19
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: File transfer through sockets

    The server reads 262144 bytes(which is guess is correct according to size specified i.e 32768*8)from file and writes 262164 bytes to socket. The extra 20 bytes are of the size of the block i think.
    ....
    Read : 262144
    Written : 262164
    ....

    The clients receives block of size 671782 bytes on an average.

    ....
    Written : 671782
    Written : 622650
    Written : 671782
    ....

    so according to me the server writes all the blocks to the socket, but clients misses out some.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: File transfer through sockets

    You are falsely assuming that the fortune cookie example is fit for every possible purpose of using TCP. In your current code if you read the block size of say... 20 bytes and there is 4GB of data available in the socket, then you read all those 4GB, completely ignoring the block size. Next time you try to read the block size again but you are at a completely arbitrary point of the stream so you are misinterpreting the block size and discarding those four bytes (and some more too because then you are falsely assuming there is a QByteArray object waiting for you in the socket). The fact that you send data in one chunk doesn't mean it will arrive in one chunk, in most cases it will not (unless you trully believe you can push `.3GB of data into a single TCP segment). Why are you using QDataStream here at all? Is that a concious decision?

    Please search the forum, this issue has been discussed countless times.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. The following user says thank you to wysota for this useful post:

    p3c0 (29th March 2012)

  6. #5
    Join Date
    May 2010
    Posts
    19
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: File transfer through sockets

    Well solved the problem.. going by the traditional way of reading chunks of data and writing to it.
    Here's the full code:

    Server Code:
    ----------------------
    Server.cpp

    Qt Code:
    1. #include "server.h"
    2. #include <QtNetwork>
    3.  
    4. Server::Server(QObject *parent) :
    5. QTcpServer(parent)
    6. {
    7. //connect(&server, SIGNAL(newConnection()),this, SLOT(acceptConnection()));
    8. listen(QHostAddress::Any, 8888);
    9. qDebug() << serverAddress() << serverPort() << serverError();
    10. }
    11.  
    12. Server::~Server()
    13. {
    14. close();
    15. }
    16.  
    17. void Server::incomingConnection(int socketDescriptor)
    18. {
    19. qDebug() << "File transfer started";
    20.  
    21. SendThread *thread = new SendThread(socketDescriptor,this);
    22. connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    23. thread->start();
    24. qDebug() << "Thread called";
    25. }
    To copy to clipboard, switch view to plain text mode 

    server.h

    Qt Code:
    1. #ifndef SERVER_H
    2. #define SERVER_H
    3.  
    4. #include <QObject>
    5. #include <QDebug>
    6. #include <QTcpServer>
    7. #include "sendthread.h"
    8.  
    9. class Server : public QTcpServer
    10. {
    11. Q_OBJECT
    12.  
    13. public:
    14. explicit Server(QObject *parent = 0);
    15. void ServerListener();
    16. ~Server();
    17.  
    18. protected:
    19. void incomingConnection(int socketDescriptor);
    20.  
    21. signals:
    22.  
    23. public slots:
    24.  
    25. };
    26.  
    27. #endif // SERVER_H
    To copy to clipboard, switch view to plain text mode 


    SendThread.cpp

    Qt Code:
    1. #include "sendthread.h"
    2. #define FILENAME "/root/Tars/Qt_SDK_Win_offline_v1_2_en.exe"
    3.  
    4. SendThread::SendThread(int socketDescriptor,QObject *parent)
    5. : QThread(parent), socketDescriptor(socketDescriptor)
    6. {
    7. }
    8.  
    9. void SendThread::run()
    10. {
    11. QTcpSocket client;
    12. qDebug() << "Thread Descriptor :" << socketDescriptor;
    13. if (!client.setSocketDescriptor(socketDescriptor))
    14. {
    15. qDebug() << client.error();
    16. return;
    17. }
    18. qDebug() << "Thread : Connected";
    19.  
    20. //send File
    21. QFile inputFile(FILENAME);
    22. QByteArray read;
    23. inputFile.open(QIODevice::ReadOnly);
    24. while(1)
    25. {
    26. read.clear();
    27. read = inputFile.read(32768*8);
    28. qDebug() << "Read : " << read.size();
    29. if(read.size()==0)
    30. break;
    31.  
    32. qDebug() << "Written : " << client.write(read);
    33. client.waitForBytesWritten();
    34. read.clear();
    35. }
    36. inputFile.close();
    37. client.disconnectFromHost();
    38. client.waitForDisconnected();
    39. qDebug() << "Thread : File transfer completed";
    40. }
    To copy to clipboard, switch view to plain text mode 


    SendThread.h

    Qt Code:
    1. #ifndef SENDTHREAD_H
    2. #define SENDTHREAD_H
    3. #include <QThread>
    4. #include <QFile>
    5. #include <QTcpSocket>
    6.  
    7. class SendThread : public QThread
    8. {
    9. public:
    10. SendThread(int socketdescriptor,QObject *parent);
    11. void run();
    12.  
    13. private:
    14. int socketDescriptor;
    15. };
    16.  
    17. #endif // SENDTHREAD_H
    To copy to clipboard, switch view to plain text mode 


    Client Code:-
    ------------------------

    Client.cpp

    Qt Code:
    1. #include "client.h"
    2.  
    3. Client::Client(QObject *parent) :
    4. QObject(parent)
    5. {
    6. client = new QTcpSocket(this);
    7. client->abort();
    8. connect(client, SIGNAL(readyRead()), this, SLOT(ReadData()));
    9. connect(client, SIGNAL(disconnected()), this, SLOT(Completed()));
    10.  
    11. }
    12.  
    13. Client::~Client()
    14. {
    15. client->close();
    16. }
    17.  
    18. void Client::start(QString address, quint16 port, QString file)
    19. {
    20. QHostAddress addr(address);
    21. filename = file;
    22. client->connectToHost(addr, port);
    23. qDebug() << client->socketDescriptor();
    24. }
    25.  
    26.  
    27. void Client::Completed()
    28. {
    29. qDebug() << "File transfer complete";
    30. }
    31.  
    32. void Client::ReadData()
    33. {
    34. QFile file(filename);
    35. if(!(file.open(QIODevice::Append)))
    36. {
    37. qDebug("File cannot be opened.");
    38. exit(0);
    39. }
    40. QByteArray read = client->read(client->bytesAvailable());
    41. qDebug() << "Read : " << read.size();
    42. file.write(read);
    43. file.close();
    44. }
    To copy to clipboard, switch view to plain text mode 

    client.h

    Qt Code:
    1. #ifndef CLIENT_H
    2. #define CLIENT_H
    3.  
    4. #include <QObject>
    5. #include <QTcpSocket>
    6. #include <QHostAddress>
    7. #include <QFile>
    8.  
    9. class Client : public QObject
    10. {
    11. Q_OBJECT
    12. public:
    13. explicit Client(QObject *parent = 0);
    14. ~Client();
    15. QTcpSocket *client;
    16. void start(QString address, quint16 port, QString file);
    17. QString filename;
    18.  
    19. private:
    20.  
    21. signals:
    22.  
    23. public slots:
    24. void ReadData();
    25. void Completed();
    26. };
    27.  
    28. #endif // CLIENT_H
    To copy to clipboard, switch view to plain text mode 

    Call Client as:

    Client c;
    c.start("192.168.10.210",8888,"/root/file1");

  7. The following user says thank you to p3c0 for this useful post:

    Quenix (4th May 2013)

  8. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: File transfer through sockets

    Oh, great... yet another one using threads for networking... /me facepalms


    By the way, if you want to transfer a file between two hosts, why don't you use something called "file transfer protocol"?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #7
    Join Date
    May 2013
    Location
    Quebec, Canada
    Posts
    7
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Thank you very much for your example. It helps me a lot to introduce me to QT code and TCP data transfer too. (I'm a student)

    I tried your code for a basic project at school : transfer a movie from a server to a client and play it on the client side.
    I just have to made some modification to your code in order to make it work properly.

    1. I had to write a waitForReadyRead in the client side because it doesn't do anything when the SIGNAL(readyRead()) happens
    Qt Code:
    1. void Client::start(QString address, quint16 port, QString file)
    2. {
    3.  
    4. QHostAddress addr(address);
    5. filename = file;
    6. client->connectToHost(addr, port);
    7. client->waitForReadyRead(); // this one have to be added
    To copy to clipboard, switch view to plain text mode 

    And, in real life, data can be much longer than we think and the server can send more than juste one packet, so the client have to read until there's no data in the Socket :
    So I just rearrange your code this way :
    Qt Code:
    1. bool Client::ClientReadData()
    2. {
    3. bool retour;
    4. QFile file(filename);
    5. QByteArray read;
    6. if(!(file.open(QIODevice::Append)))
    7. {
    8. qDebug("File cannot be opened.");
    9. exit(0);
    10. }
    11. else
    12. {
    13. while(client->waitForReadyRead())
    14. {
    15. read.clear();
    16. read = client->read(client->bytesAvailable());
    17. qDebug() << "Read : " << read.size();
    18. qDebug() << "Written : " << file.write(read);
    19. }
    20. }
    21.  
    22.  
    23. file.close();
    24. if(client->waitForReadyRead() == true)
    25. {
    26. qDebug() << "Status : OK";
    27. retour = true;
    28. }
    29. else
    30. {
    31. qDebug() << "Status : Error : there's always data on the Socket when it disconected";
    32. retour = false;
    33. }
    34. return retour;
    35. }
    To copy to clipboard, switch view to plain text mode 

    Again, thank you very much for your example and your code.

    Serge

  10. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Quote Originally Posted by Quenix View Post
    Thank you very much for your example. It helps me a lot to introduce me to QT code and TCP data transfer too. (I'm a student)

    I tried your code for a basic project at school : transfer a movie from a server to a client and play it on the client side.
    I just have to made some modification to your code in order to make it work properly.

    1. I had to write a waitForReadyRead in the client side because it doesn't do anything when the SIGNAL(readyRead()) happens
    No. The client example code was even driven, no need to call any waitForXYZ. Whenever something happens on the socket, e.g. data received, a signal will be emitted and the client code reacts to that. In the example code it reads the available data and appends it to the file.

    Your modification effetively blocks the ClientReadData() method until all data has been transferred, totally blocking the thread that executes it, needlessly introducing the need for a thread in order not to block the main thread.

    There is no need for threading here at all, it just complicates the two programs and makes them harder to debug.

    Cheers,
    _

  11. #9
    Join Date
    May 2013
    Location
    Quebec, Canada
    Posts
    7
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Quote Originally Posted by anda_skoa View Post
    No. The client example code was even driven, no need to call any waitForXYZ. Whenever something happens on the socket, e.g. data received, a signal will be emitted and the client code reacts to that. In the example code it reads the available data and appends it to the file.
    Thank you very much for your answer.

    What should I use instead of a client->waitForSomething because without this, nothing happens in the client side after the initial TCP Handshake when the server started to write in the socket.

    Quote Originally Posted by anda_skoa View Post
    Your modification effetively blocks the ClientReadData() method until all data has been transferred, totally blocking the thread that executes it, needlessly introducing the need for a thread in order not to block the main thread.

    There is no need for threading here at all, it just complicates the two programs and makes them harder to debug.
    The only way I see to do it better is to introduce a new threads, but that's because I'm a beginner ;-)
    How could it be written in a better way ?

    Thank you,

    --
    Serge

  12. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Check that you have started the main thread's event loop, i.e. called exec() on the application object.

    Cheers,
    _

  13. #11
    Join Date
    May 2013
    Location
    Quebec, Canada
    Posts
    7
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Quote Originally Posted by anda_skoa View Post
    Check that you have started the main thread's event loop, i.e. called exec() on the application object.
    I tried the code in a QT application with GUI and I create the Class Client object with a button.clicked(). When I click on the button, I thought that the QApplication::exec() happens in the main.cpp before I pressed on the button. So, normally, the main thread's event loop is supposed to be started before I click anywhere on the mainwindow .?

    Thank you very much for the time you take to answer all my newbe question :-)

    --
    Serge

  14. #12
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Yes, if you have a working GUI then the eventloop should be running.

    Hard to tell without a minimal program using the concrete code.
    All signal/slots setup correctly?

    Cheers,
    _

  15. #13
    Join Date
    May 2013
    Location
    Quebec, Canada
    Posts
    7
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Quote Originally Posted by anda_skoa View Post
    All signal/slots setup correctly?
    This is exactly the code you can see upper.
    For the rest, there's just 1 button in the client side and I used "Go to slot..." in qtdesigner to create the SIGNAL/SLOT connection.

    thanks,
    Serge

  16. #14
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: File transfer through sockets

    Well, since you claim this is all the code and the code does not contain any signal/slot connects, you are obviously missing those.

    Cheers,
    _

Similar Threads

  1. Replies: 1
    Last Post: 11th February 2011, 04:32
  2. File Transfer in Qt
    By Rajeshsan in forum Qt Programming
    Replies: 6
    Last Post: 11th February 2011, 04:13
  3. Replies: 2
    Last Post: 2nd April 2008, 17:28
  4. how to send a file over qt4 tcp sockets?
    By sha3er in forum Qt Programming
    Replies: 1
    Last Post: 11th June 2007, 16:57

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.