目标要求:
本实验主要是有一个服务器和客户端,服务器可以选择本地的文件,然后发给客户端,客户端可以选择保存的路径。同时在两边传输文件的过程中,使用进度条控件来提示文件传输进度。
主要控件有LineEdit PushButton progressBar.
涉及知识:
主要是基本控件的使用,TCP的服务器和客户端的通信流程,文件的读写,QT中信号与槽,Qt中定时器的使用,文件对话框的使用,进度条控件的使用
效果图展示:
完成文件接收发效果:
查看文件传输是否完全正确:
该项目实现基本讲解:
服务器流程图:
客户端流程图:
代码实现:
服务器:
1.添加所需要的头文件以及所需成员和槽函数
注意在使用网络模块需要在xx.pro添加QT+ =network
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QPushButton>
#include <QFileInfo>
#include <QHostAddress>
#include <QTimer>
private:
Ui::Server *ui;
QTcpServer *server; //服务器对象
QTcpSocket *socket; //网络套接字
QByteArray data; //接收数据缓冲区
QTimer *timer; //定时器对象
QFile sendfile; //文件对象
QString file; //文件路径
public slots:
void chose_file(void); //选择文件传输
2.在构造函数中添加服务器端监听IP和端口,套接字的消息读写的信号与槽代码
setWindowTitle("服务器");
resize(600,150);
//创建对象
server=new QTcpServer(this);
socket=new QTcpSocket(this);
timer=new QTimer(this);
ui->progressBar->setValue(0);
//监听IP和端口
if(!server->listen(QHostAddress("10.163.1.116"),8888))
{
qDebug()<<"服务器监听错误"<<server->errorString();
}
else {
qDebug()<<"服务器监听成功";
}
//当有新的连接时
connect(server,&QTcpServer::newConnection,[=](){
socket=server->nextPendingConnection();
qDebug()<<"有新的客户端连接!";
});
//选文件和绑定客服端IP和端口
connect(ui->chosefile_btn,&QPushButton::clicked,this,&Server::chose_file);
3.槽函数实现
void Server::chose_file()
{
//发送文件
//获取文件
file =QFileDialog::getOpenFileName(this,"打开文件","D:\\Linux_qt\\ARM\\笔记");
qDebug()<<"文件路径:"<<file;
ui->filename_edit->setText(file);
//获取文件信息
QFileInfo info(file);
QString filename=file.section('/',-1);
qDebug()<<"文件名称:"<<filename.toUtf8().data()<<"文件大小:"<<info.size();
//发送文件名称和文件大小
QString sendFileInfo=filename+"@"+QString::number(info.size());
qDebug()<<"sendFileInfo:"<<sendFileInfo;
socket->write(sendFileInfo.toUtf8());
//接收是否开始发送文件的信息
connect(socket,&QTcpSocket::readyRead,[=](){
data=socket->readAll();
qDebug()<<"test1:"<<data.data();
if(QString(data)=="我已经接收到文件信息,请开始发送文件")
{
//打开文件
//QFile sendfile(file);
sendfile.setFileName(file);
//设置打开方式
sendfile.open(QIODevice::ReadOnly);
timer->start(100);
connect(timer,&QTimer::timeout,[=](){
// 发送文件内容
static qint64 sentSize = 0;
if(sentSize<info.size())
{
QByteArray buffer = sendfile.read(40960);
qint64 ret = socket->write(buffer);
if (ret < 0)
{
qDebug() << "发送文件失败:" << socket->errorString();
}
sentSize += ret;
//qDebug()<<"发送了"<<ret<<"字节数据";
ui->progressBar->setValue((qint64)(sentSize)*100/info.size());
}
else
{
timer->stop();
sendfile.close();
}
});
}
});
}
客户端:
1.添加头文件和成员变量以及槽函数声明
#include <QTcpSocket>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QPushButton>
#include <QFileInfo>
#include <QHostAddress>
private:
Ui::Client *ui;
QTcpSocket *socket;
QString filename; // 保存文件名
QString savePath; //保存路径
qint64 fileSize; // 保存文件大小
QFile file; //文件对象
QByteArray data; //信息缓冲区
int flag; //标志位
public slots:
void save_file(void);
2.构造函数中添加连接服务器的代码,以及接收服务器发过来的消息和文件内容,将文件内容写入到创建的新文件中,设置接收文件进度条的状态
setWindowTitle("客户端");
resize(600,150);
ui->progressBar->setValue(0);
socket=new QTcpSocket(this);
flag=0;
//连接到服务器
socket->connectToHost(QHostAddress("10.163.1.116"),8888);
// 当连接成功时
connect(socket, &QTcpSocket::connected, [=]() {
qDebug() << "已连接到服务器";
});
// 当接收到数据时
connect(socket, &QTcpSocket::readyRead, [=]() {
data= socket->read(40960);
static quint64 readBytes=0;
if(flag)
{
// 如果接收到的数据大小小于文件大小,接收文件
if (readBytes != fileSize)
{
file.write(data);
readBytes += data.size();
//qDebug()<<"收到文件大小为"<<readBytes;
ui->progressBar->setValue((qint64)readBytes*100/fileSize);
}
else
{
file.close();
qDebug() << "文件接收完毕";
}
}
});
//选择保存文件路径
connect(ui->savefile_btn,&QPushButton::clicked,this,&Client::save_file);
3、槽函数实现
void Client::save_file()
{
// 处理接收到的数据
if (filename.isEmpty() && fileSize == 0)
{
QString fileInfo = QString(data);
filename=fileInfo.section('@',0,0);
fileSize=fileInfo.section('@',1,1).toLongLong();
qDebug()<<"接收到的文件名:"<<filename<<"接收到的文件大小:"<<fileSize;
//获取保存的路径
savePath = QFileDialog::getExistingDirectory(this, "选择保存路径", QDir::homePath());
if (!savePath.isEmpty())
{
// 用户选择了保存路径
savePath+="/";
savePath+=filename;
qDebug() << "选择的保存路径:" <<savePath;
ui->filename_edit->setText(savePath);
}
else
{
// 用户取消了选择
qDebug() << "用户取消选择保存路径";
return;
}
file.setFileName(savePath); // 替换为你要保存的文件路径
if (!file.open(QIODevice::WriteOnly))
{
qDebug() << "无法创建文件";
return;
}
socket->write("我已经接收到文件信息,请开始发送文件");
flag=1;
}
}
总结:
本练习比较基础,只是设计网络通信,文件的基本传输,基本控件的使用,可以是初学者练习。
优化改进的地方有:
1.可以增加服务器和客户端聊天功能
2.可以实现文件多次发送接收,不仅只限于一次
3.可以同时传输多个文件
最后如果有需要源代码的伙伴:链接在下方。给博主点一点关注吧。
https://pan.baidu.com/s/1lot7iIOui2PLyvY6Q_KPkA?pwd=JC66 提取码:JC66