网上这方面的资源不是很多,大多数都是Http的断点续传。因小项目需求需要做一个断点传输的功能,思考后自己设计了。
服务器和客户端都基于QT5.9,在这里只给出服务器传输文件到客户端,客户端上传文件到服务器原理一样。
原理如下:
- 将文件分块传输,比如每次发送4096字节。
- 保证客户端正确接收字节且写入文件,然后向服务器反馈接收成功信息。
- 服务器收到反馈信息继续进行发送。
- 暂停下载后记录断点,欲再次下载则发送断点等数据到服务器。
- 服务器收到断点后,根据断点将文件指针移动到断点位置继续发送。
在这里只给出部分代码,全部代码可查看github。
客户端:
头文件
#pragma once
#ifndef DOWNLOADFILE_H_
#define DOWNLOADFILE_H_
#include "stdafx.h
#include <QFile>
#include <QString>
#include "FileInfo.h"
//extern TcpClient * tcp;
extern QString ip;
extern int port;
extern QString globalUserName;
//只负责下载就行了
class DownloadFile : public QObject
{
Q_OBJECT
public:
explicit DownloadFile(QString,QString,int);
//这个构造函数是下载断点文件,第一个是总数据,第二个是断点位置
DownloadFile(int,QString,QString, qint64 ,qint64 ,int );
~DownloadFile();
bool insertRecord();
bool updateRecord();
private:
int index; //序号
QTcpSocket *tcpSocket; //连接服务器的socket
QTime downloadTime;
QTimer *timer;
QFile *newFile;
QByteArray inBlock;
QByteArray outBlock; //发数据给服务器
QByteArray buffer; //用来缓存的
QString fileName;
QString saveFileName; //文件路径加文件名
QString filePath;
QString openFileName; //直接打开的文件名
qint64 RtotalSize; //总共需要发送的文件大小(文件内容&文件名信息)
qint64 byteReceived; //已经接收的大小 ‘’
qint64 receiveStatus = -1; //默认为继续发送
qint64 sumBlock;
qint64 breakPoint;
qint64 cbreakPoint;
qint64 recordId;
int breakFileId;
QString breakFileName;
QString breakFilePath;
qint64 fileId;
int receiveTime; //接受的次数
double speed;
QString leftTime; //剩余时间
bool isBreakFile = false;
void init();
bool keepOn;
void countLeftTime(float);
private slots:
void receiveFile(); //从服务器下载文件到本地。
void receiveBreakFile();
void updateSpeed();
void stopReceive(int);
signals:
//void sendDisconnect(QString); //这是什么
void downloadOver(int);
void updateProgress(int, qint64, qint64);
void updateSpeedLabel(int, double,QString);
void addToBreakFile(int, qint64 recordId,int fileId,
QString fileName,QString filePath,
qint64 breakPoint);
};
#endif // !DOWNLOADFILE_H_
downlaodFile.cpp
#include "DownloadFile.h"
#include <QFileDialog>
#include <QtWin>
#include "MyMessageBox.h"
#include "Database.h"
DownloadFile::DownloadFile(QString mFileName, QString mFilePath,int num)
{
fileName = mFileName;
filePath = mFilePath; //总文件就是 filePath + fileName;
index = num;
keepOn = false;
init();
qDebug() << "new downloadFile :" <<QThread::currentThreadId()
<< keepOn;
}
//fileId的名字可能和filename不一样
DownloadFile::DownloadFile(int mFileId,QString mFileName,QString mFilePath, qint64 mBreakPoint,qint64 mRecordId, int num)
{
breakFileName = mFileName;
breakFilePath = mFilePath; //总文件就是 filePath + fileName;
breakFileId = mFileId;
cbreakPoint = mBreakPoint;
recordId = mRecordId;
index = num;
keepOn = true;
init();
}
DownloadFile::~DownloadFile()
{
//delete ui;
}
//初始化界面
void DownloadFile::init()
{
QString bs;
QString data;
tcpSocket = new QTcpSocket(); //新建一个socket
tcpSocket->abort(); //取消已有的连接
tcpSocket->connectToHost(ip, port); //将这个socket连接到服务器
byteReceived = 0;
receiveTime = 0;
if (!keepOn)
{
bs = "downloadFile";
data = bs + "#" + fileName + "#" + globalUserName;
}
else
{
bs = "downloadBreakFile";
//cbreakPoint断点处,因为等于sumblock的值
data = bs + "#" + QString::number(breakFileId) + "#" + QString::number(cbreakPoint) + "#" + globalUserName ;
}
QByteArray datasend = data.toUtf8(); //发送UTF8过去
if (tcpSocket->write(datasend))
{
qDebug() <<