QT中TCP文件传输


*免责声明:
1、视频来源于传智播客
2、此方法仅提供参考

本文代码根据B站《零基础入门六天学会QT完整版》中的P52和P53,其中视频有缺失,为了造福其他兄弟,在此补上缺失代码


首先需要创建两个类:ServerWidget和ClientWidget类

一、UI文件

1.serverwidget.ui

在这里插入图片描述

2.clientwidget.ui

在这里插入图片描述

二、.h文件

1.serverwidget.h

在这里插入图片描述

2.clientwidget.h

在这里插入图片描述

三、cpp文件

1.ClientWidget.cpp

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QMessageBox>
#include <QHostAddress>
#include <QDebug>

ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);

    //创建TCP套接字
    tcpSocket = new QTcpSocket(this);

    //设置标题
    setWindowTitle("客户端");

    //如果连接成功
    connect(tcpSocket,&QTcpSocket::connected,
            [=]()
    {
       //初始化数据
        fileName = "";
        fileSize = 0;
        recvSize = 0;
        isFile = false;

        ui->buttonConnect->setEnabled(false);
        ui->textEdit->clear();

        ui->textEdit->append("和服务器连接成功");
    });

    ui->progressBar->setValue(0);

    //当有数据可接收时
    connect(tcpSocket,&QTcpSocket::readyRead,
            [=]()
    {
        QByteArray buf = tcpSocket->readAll();  //一次收8k

        if(false == isFile)//先接受头部信息(第一条数据)
        {
            isFile = true;
            //head # filename # size
            //文件名称
            fileName = QString(buf).section("#",1,1);
            //文件大小
            fileSize = QString(buf).section("#",2,2).toInt();
            qDebug() << fileName << fileSize;

            recvSize = 0;

            file.setFileName(fileName);

            if(false == file.open(QIODevice::WriteOnly)){
                //初始化数据
                fileName = "";
                fileSize = 0;
                recvSize = 0;
                isFile = false;
                QMessageBox::warning(this,"警告","创建文件失败");
                return;
            }

            //设置进度条最大值最小值
            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(fileSize/1024);

            ui->textEdit->append(QString("正在接受文件:\n%1").arg(fileName));

        }

        else//文件数据!!!
        {
            qint64 len = file.write(buf);
            recvSize += len;
            qDebug() << len;
            ui->progressBar->setValue(recvSize/1024);

        }

        if (recvSize == fileSize)
        {
           file.close();  //接收完毕后要记得关闭文件
           ui->buttonConnect->setEnabled(true);
           tcpSocket->disconnectFromHost();  //手动断开连接

           QMessageBox::information(this,"ok","文件接受完毕");
           ui->textEdit->append("文件接受完毕");

        }
    });
}

ClientWidget::~ClientWidget()
{
    delete ui;
}

//连接按钮
void ClientWidget::on_buttonConnect_clicked()
{
    ui->progressBar->setValue(0);//设置进度条0

    //初始化操作
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditPort->text().toInt();
    if(ip.isEmpty() == true || port == 0)
    {
        QMessageBox::warning(this,"警告","ip或端口不能为空");
        return;
    }

    tcpSocket->abort();//取消已有的连接

    //连接服务器!
    tcpSocket->connectToHost(QHostAddress(ip),port);
}

2.ServerWidget.cpp

#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>
#include <QThread>

ServerWidget::ServerWidget(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::ServerWidget)
{
    ui->setupUi(this);

    //创建套接字
    tcpServer = new QTcpServer(this);

    //监听,端口:8888
    bool isOk = tcpServer->listen(QHostAddress::Any,8888);
    if(false == isOk)//监听失败
    {
        QMessageBox::warning(this,"监听","监听失败");
        return;
    }

    //设置标题
    setWindowTitle("服务器:88888");

    //设置按钮(变灰)
    ui->buttonChoose->setEnabled(false);
    ui->buttonSend->setEnabled(false);

    //当有客户端连接时,触发信号:newConnection
    connect(tcpServer,&QTcpServer::newConnection,
            [=]()
            {
                //接收客户端套接字对象,从连接请求中选择一个请求连接(取出套接字)
                tcpSocket = tcpServer->nextPendingConnection();

                //获取对方的ip和port
                QString ip = tcpSocket-> peerAddress().toString();//获取client的ip地址
                quint16 port = tcpSocket->peerPort();//获取client的端口号
                QString str = QString("[%1:%2]和服务器连接成功").arg(ip).arg(port);
                ui->textEdit->setText(str);//设置内容

                //恢复选择按钮状态
                ui->buttonChoose->setEnabled(true);
                QMessageBox::information(this,"允许","连接成功,可以选择文件发送");
            });

    //定时器处理函数
    connect(&timer,&QTimer::timeout,
            [=]()
    {
        this->timer.stop();//关闭定时器
        senFileData();
    });
}


ServerWidget::~ServerWidget()
{
    delete ui;
}



//选择文件按钮
void ServerWidget::on_buttonChoose_clicked()
{
    QString path = QFileDialog::getOpenFileName(this,"请选择所要发送的文件","../");
    if(path.isEmpty() == false)
    {
            file.setFileName(path);
            //只读方式打开文件
            bool isOk = file.open(QIODevice::ReadOnly);
            if(false == isOk)//打开文件失败
            {
                QMessageBox::warning(this,"警告","打开文件失败");
                return;
            }
            else
            {
                ui->textEdit->append("发送的文件:");
                ui->textEdit->append(path);

                //初始化数据
                fileName = "";
                fileSize = 0;
                sendSize = 0;

                //获取发送文件的信息
                QFileInfo info(path);
                fileName = info.fileName();
                fileSize = info.size();

                ui->buttonSend->setEnabled(true);//恢复发送文件按钮
                ui->buttonChoose->setEnabled(false);//选择按钮变灰

            }

    }
}

//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{
    //发送文件按钮变灰
    ui->buttonSend->setEnabled(false);

    //先发送文件头,自定义的数据,不是文件数据
    //先发送头。自定义组包, 文件名#文件大小
    QString buf = QString("head#%1#%2").arg(fileName).arg(fileSize);

    //先发头
    qint64 len = tcpSocket->write(buf.toUtf8().data());
    tcpSocket->waitForBytesWritten();//等待数据发送完毕

    ui->textEdit->append("已经在发送文件!!");

    if(len>0)//如果头部信息发送成功,开始发送文件数据
    {
        //10毫秒后在发送文件数据
        //启动定时器,定时器内容发送文件数据
        //防止tcp黏包问题
        this->timer.start(1000);//为了延时
    }
    else
    {
        file.close();
    }

}

void ServerWidget::senFileData(){

    //发送文件信息
    //发送文件
    qint64 len = 0 ;

    do{
        //每次发送2kb大小的数据,如果剩余的数据不足2kb,就发送剩余数据的大小
        char buf[2*1024]= {0};

        len = 0;
        len=file.read(  buf , sizeof(buf) );        //读数据
        len=tcpSocket->write(buf , len);            //发数据

        //发送数据需要累积
        sendSize += len;

    }while(len>0 );
    //文件数据发送完毕
    if (fileSize == sendSize)
        {
        //QMessageBox::information(this,"ok","文件发送完毕");
        ui->textEdit->append("发送成功");

        file.close();//关闭文件
        //关闭客户端
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}

3.main.cpp

在这里插入图片描述


四、运行效果图

在这里插入图片描述

以上就是视频中TCP文件传输的代码,若有发现错误可以评论指出。

  • 8
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: 可以使用QtQTcpSocket类和QTcpServer类来实现TCP文件传输。具体步骤如下: 1. 创建一个QTcpServer对象,并在其上调用listen()方法来监听来自客户端的连接请求。 2. 当有客户端连接请求到达时,QTcpServer会触发newConnection()信号。在该信号的槽函数,可以使用QTcpServer的nextPendingConnection()方法获取一个QTcpSocket对象来和客户端进行通信。 3. 在QTcpSocket对象上调用connectToHost()方法连接服务器端,或者使用已连接的QTcpSocket对象进行数据传输。 4. 在QTcpSocket对象上调用write()方法发送文件内容,或者在接收方使用QTcpSocket的readyRead()信号和read()方法接收文件内容。 5. 传输完成后,关闭QTcpSocket对象和QTcpServer对象。 具体实现可以参考Qt官方文档和示例程序。 ### 回答2: Qt是一个开发C++桌面应用程序的跨平台框架,它提供了丰富的类库和工具来简化程序开发。要实现TCP文件传输,可以借助Qt的网络模块。 首先,我们需要创建一个TCP服务器和一个TCP客户端。服务器端需要监听指定的端口并接受客户端连接,而客户端需要连接到服务器并发送文件数据。 在服务器端,我们可以使用QTcpSocket和QTcpServer类来创建一个TCP服务器。可以使用QTcpServer的listen方法来绑定服务器IP地址和监听的端口。一旦有客户端连接到服务器,QTcpServer会发出newConnection信号,我们可以在这个信号槽函数处理客户端连接。 在客户端,我们同样可以使用QTcpSocket类来创建一个TCP连接。通过调用QTcpSocket的connectToHost方法,我们可以连接到服务器的IP地址和端口。一旦连接建立成功,我们可以使用QTcpSocket的write方法来发送文件数据。 为了实现文件传输,我们可以使用QFile类来打开文件并读取数据。在服务器端,可以将文件内容分割为较小的数据块,并使用QTcpSocket的write方法将这些数据块发送给客户端。在客户端,我们可以使用QTcpSocket的read方法接收服务器发送的数据块,并将其写入文件。 在文件传输过程,我们还可以使用QTcpSocket的readyRead和bytesWritten信号来处理读取和写入文件数据的细节,以确保数据的完整性和正确性。 通过以上步骤,我们可以使用Qt实现TCP文件传输。同时,Qt还提供了其他一些类和方法来处理网络连接的错误和异常,并提供了完善的错误处理机制来增加程序的稳定性和可靠性。 ### 回答3: 在Qt实现TCP文件传输需要使用QTcpSocket类和QFile类。首先,需要创建一个QTcpSocket的实例来处理网络连接。然后,连接到服务器并通过QTcpSocket的write方法发送文件的字节流。同时,使用QFile类来打开本地文件以便读取字节流并将其发送给服务器。 以下是一个简单的示例代码: ```cpp // 客户端: QTcpSocket socket; socket.connectToHost("服务器地址", 端口号); if (socket.waitForConnected()) { QFile file("本地文件路径"); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); file.close(); socket.write(data); socket.waitForBytesWritten(); socket.disconnectFromHost(); } } else { // 连接失败的处理逻辑 } // 服务器: QTcpServer server; server.listen(QHostAddress::Any, 端口号); connect(&server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); void YourClass::onNewConnection() { QTcpSocket *socket = server.nextPendingConnection(); connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); } void YourClass::onReadyRead() { QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender()); QByteArray data = socket->readAll(); // 处理接收到的文件数据 } ``` 上面的代码只是实现了TCP文件传输的基本框架,你还可以根据自己的需求进行相关的逻辑和错误处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值