查了下资料,Http断点续传主要是Http请求包中的Range头
多线程下载需要管理好每一个线程下载的文件段
整个代码大致如下
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FengBan
{
///
/// 多线程下载、断点下载的管理类
///
class DFGManager : IDisposable
{
private string dfgFilename;
private int size;
private FileStream writer;
private SortedSet
rset = new SortedSet
(new RangeCompare());
///
/// 多线程下载、断点下载的管理类
///
///
internal DFGManager(string dfgFilename)
{
this.dfgFilename = dfgFilename;
if (File.Exists(dfgFilename))
{
ReadDFGFile();
File.Delete(dfgFilename);
}
writer = new FileStream(dfgFilename, FileMode.OpenOrCreate);
WriteDFGFile();
}
///
/// 获取或设置要下载的文件大小
///
public int Size
{
get { return size; }
set
{
size = value;
byte[] head = new byte[16];
byte[] bsize = BitConverter.GetBytes(size);
int i;
for (i = 0; i < bsize.Count(); i++)
{
head[i] = bsize[i];
}
writer.Seek(0, SeekOrigin.Begin);
writer.Write(head, 0, 16);
writer.Flush();
}
}
///
/// 释放文件段,该段已经下载完成
///
///
public void Free(Range range)
{
lock (rset)
{
var find = from r in rset
where r.left == range.left && r.status == 1
select r;
if (find.Count() == 1)
{
var ele = find.First();
ele.status = 2;
range.status = 2;
if (ele.right < range.right)
{
ele.right = range.right;
}
else
{
range.right = ele.right;
}
MergeRange();
writer.Write(BitConverter.GetBytes(range.left), 0, 4);
writer.Write(BitConverter.GetBytes(range.right), 0, 4);
writer.Flush();
}
else if (find.Count() == 0)
{
throw new Exception("找不到释放的块");
}
else
{
throw new Exception("多个符合条件的块");
}
}
}
///
/// 分配文件段
///
///
期望分配的大小
///
实际分配的大小
public Range Alloc(int expectSize = 102400)
{