欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > Qt实现文件传输服务器端(图文详解+代码详细注释)

Qt实现文件传输服务器端(图文详解+代码详细注释)

2025/4/22 22:35:38 来源:https://blog.csdn.net/qq_62435866/article/details/147213615  浏览:    关键词:Qt实现文件传输服务器端(图文详解+代码详细注释)

Qt实现文件传输服务器

  • 1、前言
  • 2、服务器
    • 2.1 服务器UI界面
    • 2.2添加网络模块和头文件
    • 2.3、创建服务器对象
    • 2.4 连接有新连接的信号与槽
    • 2.5实现有新连接处理的槽函数
    • 2.6 选择文件按钮实现
      • 2.6.1 连接按钮点击的信号与槽
      • 2.6.2 添加头文件
      • 2.6.3 创建所需对象
      • 2.6.3 选择文件按钮实现
    • 2.7 发送文件按钮实现
    • 2.7.1添加定时器解决粘包问题
    • 2.7.2 连接定时器结束信号与槽
    • 2.7.3定时器结束槽函数实现
  • 3、头文件和.cpp文件
    • 3.1 Widget.h文件
    • 3.2 .cpp文件
  • 4、总结

1、前言

记录自己对于Qt实现文件传输的学习过程,方便自己日后回顾,也可以给别人提供参考借鉴,目录就是实现的过程,大家可以按照目录逐步浏览,也可以点击目录跳转到所需部分,这个是服务器端,客户端在主页另外一篇博客。

2、服务器

2.1 服务器UI界面

在这里插入图片描述

2.2添加网络模块和头文件

在这里插入图片描述

添加完网络模块构建一下,添加头文件
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>

在这里插入图片描述

2.3、创建服务器对象

#define PORT 8000       //端口号QTcpServer *tcpServer;          //创建服务器对象指针
QTcpSocket *tcpSocket;          //通信套接字

在这里插入图片描述

在这里插入图片描述

创建服务器对象,监听连接对象
tcpServer = new QTcpServer(this);           //创建服务器对象
tcpServer->listen(QHostAddress::Any,PORT);          //监听任意ip地址和端口号

在这里插入图片描述

2.4 连接有新连接的信号与槽

创建槽函数
private slots:void newConnectionHandler();        //新连接处理槽函数
连接有新连接的信号和槽函数
connect(tcpServer,&QTcpServer::newConnection,this,&Widget::newConnectionHandler);    //处理新连接

2.5实现有新连接处理的槽函数

鼠标放在函数上,ALT+Enter,点击添加定义

在这里插入图片描述

未连接成功前设置按钮不可按
//设置按钮不可按
ui->selectPushButton->setEnabled(false);        //选择文件按钮不可按
ui->sendPushButton->setEnabled(false);          //发送文件按钮不可按

在这里插入图片描述

新连接槽函数实现
//处理新连接
void Widget::newConnectionHandler()
{//建立Tcp连接tcpSocket = tcpServer->nextPendingConnection();     //取出下一个连接的套接字   //获取ip地址和端口号QString ip = tcpSocket->peerAddress().toString();   //ip地址qint16 Port = tcpSocket->peerPort();                //端口号//显示ip地址和端口号ui->ipLineEdit->setText(ip);            //在ip输入框上显示ui->portLineEdit->setText(QString::number(Port));        //在Port输入框中显示QString connectTemp = QString("[%1:%2] 已连接").arg(ip).arg(Port);     //已连接文本ui->messageTextEdit->setText(connectTemp);          //显示已连接信息//设置文件按钮为可按ui->selectPushButton->setEnabled(true);             //设置选择文件按钮位可按ui->sendPushButton->setEnabled(true);               //设置发送文件按钮位可按
}

2.6 选择文件按钮实现

2.6.1 连接按钮点击的信号与槽

把鼠标放到选择文件的按钮控件上,右键,点击转到槽

在这里插入图片描述

点击clicked()

在这里插入图片描述

2.6.2 添加头文件

在这里插入图片描述

添加QMessageBox是为了弹窗消息框,添加QDebug是为了打印信息

2.6.3 创建所需对象

QFile file;                     //创建文件对象QString fileName;               //文件名字
qint64 fileSize;                //文件大小
qint64 senddFileSize;           //发送文件大小

在这里插入图片描述

2.6.3 选择文件按钮实现

//选择文件按钮
void Widget::on_selectPushButton_clicked()
{QString filePath = QFileDialog::getOpenFileName(this,"open","../");   //准备打开文件的路径//打开的文件路径不为空if(!filePath.isEmpty()){//获取文件信息QFileInfo fileInfo(filePath);       //文件信息fileName = fileInfo.fileName();     //文件名字fileSize = fileInfo.size();         //文件大小senddFileSize = 0;         //发送文件大小为0//以只读打开文件file.setFileName(filePath);     //准备打开的文件bool fileisOk = file.open(QIODevice::ReadOnly);         //以只读形式打开//打开文件失败if(fileisOk==false){QMessageBox::warning(this,"打开文件","打开文件失败");     //显示打开文件失败消息框}//文件路径显示ui->messageTextEdit->setText(filePath);         //显示文件路径ui->selectPushButton->setEnabled(false);       //打开文件成功后选择文件按钮失效ui->sendPushButton->setEnabled(true);          //发送按钮文件生效  }else{QMessageBox::warning(this,"打开文件失败","文件不能为空");      //显示打开文件错误消息框}}

2.7 发送文件按钮实现

跟选择文件一样,转到槽,点击clicked()

2.7.1添加定时器解决粘包问题

添加头文件

在这里插入图片描述

创建定时器对象
QTimer sendFileTimer;           //发送文件定时器

2.7.2 连接定时器结束信号与槽

创建定时器结束处理槽函数
void sendFileTimeoutHandler();          //发送文件结束定时器处理
sendFileTimer = new QTimer(this);           //创建定时器对象
连接定时器结束信号与槽
connect(sendFileTimer,&QTimer::timeout,this,&Widget::sendFileTimeoutHandler); //定时器结束处理       

2.7.3定时器结束槽函数实现

//定时器结束处理
void Widget::sendFileTimeoutHandler()
{sendFileTimer->stop();          //停止定时器char buf[4*1024] = {0};       //缓冲区qint64 bytesRead = file.read(buf, sizeof(buf)); // 读取实际字节数//成功读取到数据if(bytesRead>0){qint64 bytesWritten = tcpSocket->write(buf, bytesRead); // 发送实际读取的字节//发送错误if (bytesWritten == -1) {QMessageBox::warning(this, "错误", "发送失败");return;}senddFileSize += bytesWritten;     //发送的文件大小// 未发送完则继续触发定时器if (senddFileSize < fileSize) {sendFileTimer->start(20);       //20ms触发一次定时器} else {QMessageBox::information(this, "完成", "文件发送完毕");file.close();}}else if(senddFileSize < fileSize){QMessageBox::warning(this, "错误", "文件读取失败");}
}

3、头文件和.cpp文件

3.1 Widget.h文件

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFileDialog>
#include <QFileInfo>
#include <QFile>
#include <QMessageBox>
#include <QDebug>
#include <QTimer>#define PORT 8000       //端口号QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void newConnectionHandler();            //新连接处理槽函数void sendFileTimeoutHandler();          //发送文件结束定时器处理void on_selectPushButton_clicked();     //选择文件按钮实现void on_sendPushButton_clicked();       //发送文件按钮实现private:Ui::Widget *ui;QTcpServer *tcpServer;          //创建服务器对象指针QTcpSocket *tcpSocket;          //通信套接字QFile file;                     //创建文件对象QString fileName;               //文件名字qint64 fileSize;                //文件大小qint64 senddFileSize;           //发送文件大小QTimer *sendFileTimer;           //发送文件定时器
};
#endif // WIDGET_H

3.2 .cpp文件

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
//    this->setWindowFlag(Qt::FramelessWindowHint);       //去边框//设置按钮不可按ui->selectPushButton->setEnabled(false);        //选择文件按钮不可按ui->sendPushButton->setEnabled(false);          //发送文件按钮不可按tcpServer = new QTcpServer(this);           //创建服务器对象tcpServer->listen(QHostAddress::Any,PORT);          //监听任意ip地址和端口号sendFileTimer = new QTimer(this);           //创建定时器对象connect(tcpServer,&QTcpServer::newConnection,this,&Widget::newConnectionHandler);    //处理新连接connect(sendFileTimer,&QTimer::timeout,this,&Widget::sendFileTimeoutHandler);        //定时器结束处理
}Widget::~Widget()
{delete ui;
}//处理新连接
void Widget::newConnectionHandler()
{//建立Tcp连接tcpSocket = tcpServer->nextPendingConnection();     //取出下一个连接的套接字//获取ip地址和端口号QString ip = tcpSocket->peerAddress().toString();   //ip地址qint16 Port = tcpSocket->peerPort();                //端口号//显示ip地址和端口号ui->ipLineEdit->setText(ip);            //在ip输入框上显示ui->portLineEdit->setText(QString::number(Port));        //在Port输入框中显示QString connectTemp = QString("[%1:%2] 已连接").arg(ip).arg(Port);     //已连接文本ui->messageTextEdit->setText(connectTemp);          //显示已连接信息//设置文件按钮为可按ui->selectPushButton->setEnabled(true);             //设置选择文件按钮位可按ui->sendPushButton->setEnabled(true);               //设置发送文件按钮位可按}//定时器结束处理
void Widget::sendFileTimeoutHandler()
{sendFileTimer->stop();          //停止定时器char buf[4*1024] = {0};       //缓冲区qint64 bytesRead = file.read(buf, sizeof(buf)); // 读取实际字节数//成功读取到数据if(bytesRead>0){qint64 bytesWritten = tcpSocket->write(buf, bytesRead); // 发送实际读取的字节//发送错误if (bytesWritten == -1) {QMessageBox::warning(this, "错误", "发送失败");return;}senddFileSize += bytesWritten;     //发送的文件大小// 未发送完则继续触发定时器if (senddFileSize < fileSize) {sendFileTimer->start(20);       //20ms触发一次定时器} else {QMessageBox::information(this, "完成", "文件发送完毕");file.close();}}else if(senddFileSize < fileSize){QMessageBox::warning(this, "错误", "文件读取失败");}
}//选择文件按钮
void Widget::on_selectPushButton_clicked()
{QString filePath = QFileDialog::getOpenFileName(this,"open","../");   //准备打开文件的路径//打开的文件路径不为空if(!filePath.isEmpty()){//获取文件信息QFileInfo fileInfo(filePath);       //文件信息fileName = fileInfo.fileName();     //文件名字fileSize = fileInfo.size();         //文件大小senddFileSize = 0;         //发送文件大小为0//以只读打开文件file.setFileName(filePath);     //准备打开的文件bool fileisOk = file.open(QIODevice::ReadOnly);         //以只读形式打开//打开文件失败if(fileisOk==false){QMessageBox::warning(this,"打开文件","打开文件失败");     //显示打开文件失败消息框}//文件路径显示ui->messageTextEdit->setText(filePath);         //显示文件路径ui->selectPushButton->setEnabled(false);       //打开文件成功后选择文件按钮失效ui->sendPushButton->setEnabled(true);          //发送按钮文件生效}else{QMessageBox::warning(this,"打开文件失败","文件不能为空");      //显示打开文件错误消息框}}//发送文件按钮
void Widget::on_sendPushButton_clicked()
{//发送文件信息QString fileMes = QString("%1##%2\n").arg(fileName).arg(fileSize);       //发送文件的名字和大小qint64 fileLength = tcpSocket->write(fileMes.toUtf8().data());     //发送文件长度//发送文件成功if(fileLength > 0){//发送文件的真正内容//距离太久会产生粘包问题//使用定时器解决粘包问题sendFileTimer->start(20);    //间隔20ms触发timeout定时器结束信号}else{QMessageBox::warning(this,"发送文件","发送文件失败");          //显示发送文件失败消息框file.close();           //关闭文件tcpSocket->disconnectFromHost();        //断开连接tcpSocket->close();       //关闭连接}
}

4、总结

以上就是Qt实现文件传输服务器端的整个过程了,浏览过程中,如若发现错误,欢迎大

家指正,有问题的可以评论区留言或者私信。最后,如果大家觉得有所帮助,可以点一

下赞,谢谢大家!未来是未知的,愿大家保持冷静,继续前行!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词