【问题标题】:How to send a file in Qt?如何在 Qt 中发送文件?
【发布时间】:2015-07-29 01:59:31
【问题描述】:

我正在尝试将文件从客户端发送到服务器。但它只发送文件的一部分。似乎当文件大小超过 2Mb 时会发生这种情况。可能是什么问题?抱歉,如果这是一个愚蠢的问题,但我在 Google 中找不到答案。

这是客户端 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";
    }
}

这是一个服务器:

#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();
    }
}

【问题讨论】:

    标签: c++ qt client server


    【解决方案1】:

    到目前为止,我还没有遇到同样的问题。所以我找到了一些解决方案。对大约 200Mb 的文件进行测试,我发现没有问题。

    发件人部分:

    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
        }
    }
    

    服务器部分:

    我将我的服务器指定为:

    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;
    };
    

    以及实现:

    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();
    }
    

    如您所见,我创建了新类 SocketThread 用于接收我需要的多标题服务器。

    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();
    }
    

    我希望您能够使我的代码适应您的项目。最好的问候

    【讨论】:

    • 你好,非常感谢你的回复,你能把整个项目发给我吗,这将是一个很好的例子吗?我是 Qt 的新手,所以对我来说会更容易。
    • 没问题,here Github 链接。描述的模块:Agent-Win64 的 Filesender、Server-Win64 的 Server 和 SocketThread
    • 好例子,斯帕西博
    【解决方案2】:

    Vlad,我建议您查看一个 Qt 示例,例如:http://doc.qt.io/qt-5/qtbluetooth-btfiletransfer-example.html

    忽略 BT 特定的东西,看看它做了什么。

    如果我有一个可以编译的独立代码,我想我可以为您提供更多帮助...即,您没有发布标题、主文件等。 做一个拉链,把它拉到某个地方,当我迟交报告回来时,我可以试着看看它有什么问题! =]

    【讨论】:

    【解决方案3】:

    我一直在寻找相同的解决方案。最后,我可以在没有 QDataStream 的情况下将文件传输到 635MB

    我只是使用下面的代码。

    为客户。

    void MyClient::establishConnection(QString ip, quint16 port){
    
    this->ip = ip;
    this->port = port;
    
    socket = new QTcpSocket();
    socket->connectToHost(ip, port);
    
    socket->waitForConnected(3000);
    QFile file("D:/dummy.txt");   //file path      
    file.open(QIODevice::ReadOnly);
    QByteArray q = file.readAll();
    socket->write(q);
    }
    

    为服务器

    void MyThread::readyRead(){
    
    
    QByteArray line = socket->readAll();
    
    QFile target;
    target.setFileName("D:/new1.txt");
    
    
    if (!target.open(QIODevice::WriteOnly | QIODevice::Append)) {
        qDebug() << "Can't open file for written";
        return;
    }
    target.write(line);
    
    target.close();
    
    qDebug() << "file size: " << target.size();
    
    qDebug() << "Finished!";
    
    
    }
    

    现在,我的问题是如果我使用 QDataStream 会有什么效果?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2021-09-02
      • 2017-07-29
      • 1970-01-01
      • 2021-04-09
      • 2020-07-10
      相关资源
      最近更新 更多