什么是Http的断点上传和下载
断点上传:在向服务商上传大文件的时候,将一个大的文件拆分成多个小的文件,每个文件通过单独的Http请求上传给服务器。
断点下载:在向服务器请求下载一个大的资源文件的时候,不是一次Http请求返回所有的资源文件内容。而是先通过Head请求,拿到资源文件的大小(单位:字节)。然后每次请求只请求一部分字节的数据,将请求到的数据在本地进行拼接。
断点上传和下载的优点
1、避免网络中断时,重传所有资源文件内容。
2、提高服务器并发,防止单个客户端长时间和服务器保持连接。
3、可以实时显示上传和下载的进度。
断点上传和下载的缺点
1、占用更多的网络带宽,因为每次Http请求都会附带各种额外的信息。
2、上传和下载的时间会变得长一点,因为是通过多次请求来完成断点上传和下载。
实现基本原理
依赖Http协议的几个基本的协议头来完成断点上传和下载。
1、Content-Range
:这是一个响应头,表示请求的资源文件大小,我们可以通过Head请求拿到的资源文件的字节数,就是读取的这个字段。
2、Range
:这是一个请求头,表示客户端要请求的数组的范围。如如:"0-1000"、"1001-2000"、"2001-3000"等,服务器接收到这个请求头之后,只给我们返回对应范围内的资源字节数组,不会把所有的字节数都返回给我们。
一般请求下,这两个请求头就可以实现简单的断点上传和下载。本篇文章我们使用一个WPF项目演示断点下载。
string url = "http://file.cshelloworld.com/images/1771477326069108736.jpg";
long totalSize = 0;//文件总大小
long downLoadingSize = 0;//当前已经下载了多少
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
//获取到文件总大小 通过head请求
using HttpClient client = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Head, url);
var response = await client.SendAsync(requestMessage);
totalSize = response.Content.Headers.ContentLength.Value;
using FileStream fileStream = new FileStream("d:\\a.jpj", FileMode.Create, FileAccess.Write, FileShare.Read);
//开始分片下载
while (downLoadingSize < totalSize)
{
//组装range 0,1000 1000,2000 0,9999
long start = downLoadingSize;
long end = start + 1000;
if (end > (totalSize - 1))
{
end = totalSize - 1;
}
client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end);
var res = await client.GetAsync(url);
byte[] bytes = await res.Content.ReadAsByteArrayAsync();
await fileStream.WriteAsync(bytes, 0, bytes.Length);
//更新UI的进度
downLoadingSize += bytes.Length;
int process = (int)((downLoadingSize / (decimal)totalSize) * 100);
this.Dispatcher.Invoke(() =>
{
cont.Text = process + "%";
this.processBar.Value = process;
});
}
fileStream.Close();
});
}
在以上代码中,首先是Head请求获取资源文件大小。
我们主要通过以下代码实现,通过设置HttpMethod.Head
构建一个HttpRequestMessage
的请求对象
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Head, url);
其次是断点下载过程中,Range请求头如何设置:
client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end);
每次请求到字节数组之后,我们将字节数组写入到本地的文件流中,如果网络断开,下次请求的时候,读取本地文件大小,假设本地未见大小为1000,那么我们请求的时候Range就从1001开始,这样服务器就给我们返回的是1001之后的字节数组了。
当然在这个过程中,我们还要考虑一个问题,如果服务器的资源文件发生了修改会怎么样。如果我们继续下载的话 ,就会出现问题。因为客户端下载的文件都不是同一个文件。这种情况下,我们可以使用Http的请求头Last-Modified
来判断文件是否修改,这个请求头表示文件的最近一次修改时间。当我们第一次请求数据的时候可以把这个请求头的时间记录下来,后续请求如果服务器资源文件发生变化,我们就将本地文件全部删除,然后重新发起请求。
联系站长
站长公众号
推荐阅读
-
C#弃元表达式的用法
-
记录一次JSON.NET反序列化带来的内存爆炸问题
-
C#如何使用HttpClient对大文件进行断点上传和下载
-
Windows Api如何创建一个快捷方式并且在开始菜单搜索到自己的应用
-
.NET Core配置文件发生变更的时候,程序如何接受
-
C#如何将文件压缩成ZIP并且实时显示压缩进度
-
线性表
-
顺序栈
-
链栈
-
数组实现队列