QT TCP网络编程(二、发送文件)

本文详细介绍了在QT5.14.1环境下,如何实现TCP网络编程的客户端和服务器端文件传输功能。包括客户端的打开文件、连接、发送文件头及数据、错误处理,以及服务器端的监听、接受连接、接收文件、更新进度条和错误处理等关键步骤。示例代码清晰地展示了整个文件传输的过程。
摘要由CSDN通过智能技术生成

        环境QT 5.14.1,本文实现了 1、客户端和服务器端发送文件功能。
      在文章开头先推荐一篇自己写的TCP、UDP、IP的文章,个人感觉挺不错的,有兴趣的伙伴们可以点开看看:看完这篇博客之后,含着泪学会了TCP/IP_断点-CSDN博客

 

本文作者原创,转载请附上文章出处与本文链接。

QT TCP网络编程(二、发送文件)目录

一、软件界面

 1. 服务器界面截图

2. 客户端界面截图 

二、引入抬头 (以下部分为正文部分)

三、客户端编程

 1. dialog_c.h

2. dialog_c.cpp

2.1 构造函数代码

2.2 实现打开文件函数

2.3 实现连接函数

2.4 实现文件头结构的发送

2.5 更新进度条发送文件数据

2.6 错误处理函数

四、服务器编程

1. dialog_s.h

2. dialog_s.cpp

2.1 构造函数

2.2 监听函数

2.3 接受连接函数

2.4 更新进度条函数

2.5 错误处理函数


一、软件界面

 1. 服务器界面截图

 

2. 客户端界面截图 

二、引入抬头 (以下部分为正文部分)

1. 在.pro文件中添加QT += network,否则是访问不到<QTcpSocket>

//项目的.pro文件中添加QT += network

//添加完network才能使用<QTcpSocket>

QT += network

三、客户端编程

 1. dialog_c.h

QTcpSocket *tcpClient;
    QFile *localFile;  //要发送的文件
    qint64 totalBytes;  //数据总大小
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QString fileName;  //保存文件路径
QByteArray outBlock;  //数据缓冲区,即存放每次要发送的数据

private slots:
    void send();  //连接服务器
    void startTransfer();  //发送文件大小等信息
    void updateClientProgress(qint64); //发送数据,更新进度条
    void displayError(QAbstractSocket::SocketError); //显示错误
void openFile();  //打开文件

2. dialog_c.cpp

2.1 构造函数代码

loadSize = 4*1024;
totalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
tcpClient = new QTcpSocket(this);
//当连接服务器成功时,发出connected()信号,我们开始传送文件
connect(tcpClient,SIGNAL(connected()),this,SLOT(startTransfer()));
//当有数据发送成功时,我们更新进度条
connect(tcpClient,SIGNAL(bytesWritten(qint64)),this,
       SLOT(updateClientProgress(qint64)));
connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,
       SLOT(displayError(QAbstractSocket::SocketError)));
//开始使”发送“按钮不可用
ui->sendButton->setEnabled(false);

2.2 实现打开文件函数

void Widget::openFile()   //打开文件
{
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
    {
       ui->sendButton->setEnabled(true);
       ui->clientStatusLabel->setText(tr("打开文件 %1 成功!")
                                       .arg(fileName));
    }
}

2.3 实现连接函数

    ui->sendButton->setEnabled(false);
    bytesWritten = 0;
    //初始化已发送字节为0
    ui->clientStatusLabel->setText(tr("连接中..."));
    tcpClient->connectToHost(ui->hostLineEdit->text(),
                             ui->portLineEdit->text().toInt());//连接

2.4 实现文件头结构的发送

    localFile = new QFile(fileName);
    if(!localFile->open(QFile::ReadOnly))
    {
       qDebug() << "open file error!";
       return;
    }

    //文件总大小
    totalBytes = localFile->size();

    QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_4_6);
QString currentFileName = fileName.right(fileName.size()
- fileName.lastIndexOf('/')-1);

    //依次写入总大小信息空间,文件名大小信息空间,文件名
    sendOut << qint64(0) << qint64(0) << currentFileName;

    //这里的总大小是文件名大小等信息和实际文件大小的总和
    totalBytes += outBlock.size();

    sendOut.device()->seek(0);
    //返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
    sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));

    //发送完头数据后剩余数据的大小
    bytesToWrite = totalBytes - tcpClient->write(outBlock);

    ui->clientStatusLabel->setText(tr("已连接"));
    outBlock.resize(0);

2.5 更新进度条发送文件数据

    //已经发送数据的大小
    bytesWritten += (int)numBytes;

    if(bytesToWrite > 0) //如果已经发送了数据
    {
   //每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,
   //就发送剩余数据的大小
       outBlock = localFile->read(qMin(bytesToWrite,loadSize));

       //发送完一次数据后还剩余数据的大小
       bytesToWrite -= (int)tcpClient->write(outBlock);

       //清空发送缓冲区
       outBlock.resize(0);

    } else {
       localFile->close(); //如果没有发送任何数据,则关闭文件
    }

    //更新进度条
    ui->clientProgressBar->setMaximum(totalBytes);
    ui->clientProgressBar->setValue(bytesWritten);

    if(bytesWritten == totalBytes) //发送完毕
    {
     ui->clientStatusLabel->setText(tr("传送文件 %1 成功")
.arg(fileName));
       localFile->close();
       tcpClient->close();
    }

2.6 错误处理函数

    qDebug() << tcpClient->errorString();
    tcpClient->close();
    ui->clientProgressBar->reset();
    ui->clientStatusLabel->setText(tr("客户端就绪"));
    ui->sendButton->setEnabled(true);

四、服务器编程

1. dialog_s.h

QTcpServer tcpServer;
QTcpSocket *tcpServerConnection;
qint64 totalBytes;  //存放总大小信息
qint64 bytesReceived;  //已收到数据的大小
qint64 fileNameSize;  //文件名的大小信息
QString fileName;   //存放文件名
QFile *localFile;   //本地文件
QByteArray inBlock;   //数据缓冲区

private slots:
    void on_startButton_clicked();
    void start();   //开始监听
    void acceptConnection();  //建立连接
void updateServerProgress();  //更新进度条,接收数据

//显示错误
void displayError(QAbstractSocket::SocketError socketError);

2. dialog_s.cpp

2.1 构造函数

totalBytes = 0;
    bytesReceived = 0;
fileNameSize = 0;

//当发现新连接时发出newConnection()信号
    connect(&tcpServer,SIGNAL(newConnection()),this,
SLOT(acceptConnection()));

2.2 监听函数

    ui->startButton->setEnabled(false);
    bytesReceived =0;
    if(!tcpServer.listen(QHostAddress::LocalHost,6666))
    {
       qDebug() << tcpServer.errorString();
       close();
       return;
    }
    ui->serverStatusLabel->setText(tr("监听"));

2.3 接受连接函数

    tcpServerConnection = tcpServer.nextPendingConnection();
connect(tcpServerConnection,SIGNAL(readyRead()),this,
SLOT(updateServerProgress()));
    connect(tcpServerConnection,
SIGNAL(error(QAbstractSocket::SocketError)),this,
           SLOT(displayError(QAbstractSocket::SocketError)));
    ui->serverStatusLabel->setText(tr("接受连接"));
    tcpServer.close();

2.4 更新进度条函数

   QDataStream in(tcpServerConnection);
   in.setVersion(QDataStream::Qt_4_6);
   if(bytesReceived <= sizeof(qint64)*2)
   { //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息
       if((tcpServerConnection->bytesAvailable() >= sizeof(qint64)*2)
           && (fileNameSize == 0))
       { //接收数据总大小信息和文件名大小信息
           in >> totalBytes >> fileNameSize;
           bytesReceived += sizeof(qint64) * 2;
       }
       if((tcpServerConnection->bytesAvailable() >= fileNameSize)
           && (fileNameSize != 0))
       {  //接收文件名,并建立文件
           in >> fileName;
           ui->serverStatusLabel->setText(tr("接收文件 %1 ...")
                                           .arg(fileName));
           bytesReceived += fileNameSize;
           localFile= new QFile(fileName);
           if(!localFile->open(QFile::WriteOnly))
           {
                qDebug() << "open file error!";
                return;
           }
       }
       else return;
   }
   if(bytesReceived < totalBytes)
   {  //如果接收的数据小于总数据,那么写入文件
      bytesReceived += tcpServerConnection->bytesAvailable();
      inBlock= tcpServerConnection->readAll();
      localFile->write(inBlock);
      inBlock.resize(0);
   }
//更新进度条
   ui->serverProgressBar->setMaximum(totalBytes);
   ui->serverProgressBar->setValue(bytesReceived);

   if(bytesReceived == totalBytes)
   { //接收数据完成时
    tcpServerConnection->close();
    localFile->close();
    ui->startButton->setEnabled(true);
ui->serverStatusLabel->setText(tr("接收文件 %1 成功!")
.arg(fileName));
   }

2.5 错误处理函数

    qDebug() << tcpServerConnection->errorString();
    tcpServerConnection->close();
    ui->serverProgressBar->reset();
    ui->serverStatusLabel->setText(tr("服务端就绪"));
    ui->startButton->setEnabled(true);

本文Demo执行程序具体请看 开源项目、开源库、闭源库、SDK 专栏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

双子座断点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值