How to send a file in Qt?

10,037

Not so far i faced the same problem. So i find some solution. Test it on files about ~200Mb, no problems i see.

Sender part:

void FileSender::send()
{
    QTcpSocket *socket = new QTcpSocket;

    connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));

    // specified m_host and m_port to yours
    socket->connectToHost(m_host, m_port);
    socket->waitForConnected();

    if ( (socket->state() != QAbstractSocket::ConnectedState) || (!m_file->open(QIODevice::ReadOnly)) ) {
        qDebug() << "Socket can't connect or can't open file for transfer";
        delete socket;
        return;
    }

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_4);

    // This part i  need to send not only file, but file name too
    // Erase it if you needn't it 
    out << (quint32)0 << m_file->fileName();

    QByteArray q = m_file->readAll();
    block.append(q);
    m_file->close();

    out.device()->seek(0);
    // This difference appear because of we send file name
    out << (quint32)(block.size() - sizeof(quint32));

    qint64 x = 0;
    while (x < block.size()) {
        qint64 y = socket->write(block);
        x += y;
        //qDebug() << x;    // summary size you send, so you can check recieved and replied sizes
    }
}

Server part:

I specified my server as :

class Server : public QTcpServer
{
    Q_OBJECT
public:
    explicit Server(QHostAddress host = QHostAddress::Any,
                    quint16 port      = Constants::Server::DEFAULT_PORT,
                    QObject *parent   = 0);
    ~Server();

public slots:
    void start();

protected:
    void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;

private:
    QHostAddress m_host;
    quint16      m_port;
};

And realization:

Server::Server(QHostAddress host, quint16 port, QObject *parent)
    : QTcpServer(parent),
      m_host(host),
      m_port(port)
{
    ...
    // your settings init there
}

void Server::start()
{
    if ( this->listen(m_host, m_port) )
        qDebug() << "Server started at " << m_host.toString() << ":" << m_port;
    else
        qDebug() << "Can't start server";
}

void Server::incomingConnection(qintptr handle)
{
    qDebug() << "incomingConnection = " << handle;
    SocketThread *thread = new SocketThread(handle);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    thread->start();
}

As you can see i create new class SocketThread for receiving as multitheading server i need.

class SocketThread : public QThread
{
    Q_OBJECT
public:
    SocketThread(qintptr descriptor, QObject *parent = 0);
    ~SocketThread();

protected:
    void run() Q_DECL_OVERRIDE;

signals:
    void onFinishRecieved();

private slots:
    void onReadyRead();
    void onDisconnected();

private:
    qintptr     m_socketDescriptor;
    QTcpSocket *m_socket;
    qint32      m_blockSize;
};


SocketThread::SocketThread(qintptr descriptor, QObject *parent)
    : QThread(parent),
      m_socketDescriptor(descriptor),
      m_blockSize(0)
{
}

SocketThread::~SocketThread()
{
    delete m_socket;
}

void SocketThread::run()
{
    m_socket = new QTcpSocket;
    m_socket->setSocketDescriptor(m_socketDescriptor);

    connect(m_socket, SIGNAL(readyRead()),    this, SLOT(onReadyRead()),    Qt::DirectConnection);
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);

    exec();
}

void SocketThread::onReadyRead()
{
    QDataStream in(m_socket);
    in.setVersion(QDataStream::Qt_5_4);

    if (m_blockSize == 0) {
        if (m_socket->bytesAvailable() < sizeof(quint32))
        return;
        in >> m_blockSize;
    }
    if (m_socket->bytesAvailable() < m_blockSize)
        return;

    QString fileName;
    // get sending file name
    in >> fileName;
    QByteArray line = m_socket->readAll();

    QString filePath = "YOUR"; // your file path for receiving  
    fileName = fileName.section("/", -1);
    QFile target(filePath + "/" + fileName);

    if (!target.open(QIODevice::WriteOnly)) {
        qDebug() << "Can't open file for written";
        return;
    }
    target.write(line);

    target.close();

    emit onFinishRecieved();
    m_socket->disconnectFromHost();
}

void SocketThread::onDisconnected()
{
    m_socket->close();

    // leave event loop
    quit();
}

I hope you will be able to adapt my code to your project. Best regards

Share:
10,037

Related videos on Youtube

Vlad
Author by

Vlad

Updated on September 15, 2022

Comments

  • Vlad
    Vlad over 1 year

    I'm trying to send a file from client to server. But it sends only a part of file. Seems like it happens when the size of file is more than 2Mb. What can be the problem? Sorry if it's a stupid question but I can't find an answer in Google.

    This is client cpp:

    #include "widget.h"
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent)
    {
        progressBar = new QProgressBar(this);
    
        tcpSocket = new QTcpSocket(this);
    
        fileLabel = new QLabel(this);
        progressLabel = new QLabel(this);
    
        fileBtn = new QPushButton(this);
        fileBtn->setText("Open");
    
        sendBtn = new QPushButton(this);
        sendBtn->setText("Send");
    
        layout = new QGridLayout;
        layout->addWidget(fileBtn, 0, 0);
        layout->addWidget(sendBtn, 0, 1);
        layout->addWidget(fileLabel, 1, 0);
        layout->addWidget(progressBar, 2, 0);
    
        connect(fileBtn, &QPushButton::clicked, this, &Widget::fileOpened);
        connect(sendBtn, &QPushButton::clicked, this, &Widget::onSend);
    
        setLayout(layout);
    }
    
    Widget::~Widget()
    {
    }
    
    void Widget::fileOpened()
    {
        fileName = QFileDialog::getOpenFileName(this, tr("Open file"));
        QFileInfo fileInfo(fileName);
        fileLabel->setText(fileInfo.fileName() + " : " + QString::number(fileInfo.size()));
        qDebug() << fileName;
    }
    
    void Widget::onSend()
    {
        tcpSocket->connectToHost("127.0.0.1", 33333);
        QFile file(fileName);
    
        QDataStream out(tcpSocket);
        int size = 0;
    
        if (file.open(QIODevice::ReadOnly))
        {
            QFileInfo fileInfo(file);
            QString fileName(fileInfo.fileName());
    
            out << fileName;
            qDebug() << fileName;
            out << QString::number(fileInfo.size());
            qDebug() << fileInfo.size();
    
            progressBar->setMaximum(fileInfo.size());
    
            while (!file.atEnd())
            {
                QByteArray rawFile;
                rawFile = file.read(5000);
                //false size inc
                QFileInfo rawFileInfo(rawFile);
                size += rawFileInfo.size();
                out << rawFile;
                progressBar->setValue(rawFile.size());
                qDebug() << QString::number(fileInfo.size());
                qDebug() << "ToSend:"<< rawFile.size();
            }
            out << "#END";
        }
    }
    

    This is a server one:

    #include "myserver.h"
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent)
    {
        startBtn = new QPushButton(this);
        startBtn->setText("Connect");
    
        progressBar = new QProgressBar(this);
    
        layout = new QGridLayout;
        layout->addWidget(startBtn, 0, 0);
        layout->addWidget(progressBar, 1, 0);
    
        connect(startBtn, &QPushButton::clicked, this, &MainWindow::on_starting_clicked);
    
        setCentralWidget (new QWidget (this));
        centralWidget()->setLayout(layout);
    }
    
    MainWindow::~MainWindow()
    {
        server_status=0;
    }
    
    void MainWindow::on_starting_clicked()
    {
        startBtn->setText("Connecting...");
        tcpServer = new QTcpServer(this);
        connect(tcpServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
        if (!tcpServer->listen(QHostAddress::Any, 33333) && server_status==0)
        {
            qDebug() <<  QObject::tr("Unable to start the server: %1.").arg(tcpServer->errorString());
        }
        else
        {
            server_status=1;
            qDebug() << QString::fromUtf8("Сервер запущен!");
            startBtn->setText("Running");
        }
    }
    
    void MainWindow::acceptConnection()
    {
    
        qDebug() << QString::fromUtf8("У нас новое соединение!");
        tcpServerConnection = tcpServer->nextPendingConnection();
        connect(tcpServerConnection,SIGNAL(readyRead()),this, SLOT(slotReadClient()));
        // tcpServer->close();
    
        QDir::setCurrent("/Users/vlad/Desktop/");
        QString fileName;
        QString fileSize;
    
    }
    
    
    void MainWindow::slotReadClient()
    {
        QDataStream in(tcpServerConnection);
        QByteArray z;
    
        if (!isInfoGot)
        {
            isInfoGot = true;
            in >> fileName;
            qDebug() << fileName;
            in >> fileSize;
            qDebug() << fileSize;
        }
        QFile loadedFile(fileName);
    
        if (loadedFile.open(QIODevice::Append))
        {
            while (tcpServerConnection->bytesAvailable())
            {
                qDebug() << "bytesAvailable:" << tcpServerConnection->bytesAvailable();
                in >> z;
                qDebug() << z;
                loadedFile.write(z);
    
            }
            loadedFile.close();
        }
    }
    
  • Vlad
    Vlad almost 9 years
    github.com/ruspython/QtFileClient github.com/ruspython/QtFileServer I've uploaded projects on github, thanks for your reply
  • Vlad
    Vlad almost 9 years
    Hello, thanks a lot for yout reply, could you send me the whole project, it would be a great example? I'm new in Qt, so it would be easier for me.
  • t3ft3l--i
    t3ft3l--i almost 9 years
    No problem, here Github link. Described modules: Filesender at Agent-Win64, Server and SocketThread at Server-Win64
  • Vlad
    Vlad almost 9 years
    Good example, spasibo