using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
class HttpMultiThreadDownload
{
const int _bufferSize = 1024 * 16;
public DownLoadForm Form { get; set; }
//线程ID
public int ThreadID { get; set; }
//文件URI
public string URI { get; set; }
//线程回调
Action<DownloadState, float> Callback = null;
public HttpMultiThreadDownload(DownLoadForm form, int threadID, Action<DownloadState, float> callback)
{
Form = form;
ThreadID = threadID;
URI = form.SourceURI;
Callback = callback;
}
//析构方法
~HttpMultiThreadDownload()
{
Form.Dispose();
}
public void Receive()
{
//线程临时文件
string fileName = Form.fileNames[ThreadID];
//接收缓冲区
byte[] buffer = new byte[_bufferSize];
//接收字节数
int readSize = 0;
Stream stream = null;
//Log.LogDebug.Print(" 线程[" + ThreadID.ToString() + "] 开始接收......");
while (true)
{
if (!Form.isPause)
{
using (FileStream fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
{
try
{
long currentLen = fileStream.Length;
Form.hasReceived[ThreadID] = (int)currentLen;
Form.restartPos[ThreadID] = Form.startPos[ThreadID] + Form.hasReceived[ThreadID];
fileStream.Seek(Form.hasReceived[ThreadID], SeekOrigin.Begin);//seek
HttpWebRequest request;
if (URI.StartsWith("https", StringComparison.OrdinalIgnoreCase))//https
{
ServicePointManager.ServerCertificateValidationCallback
= new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
=> { return true; });
request = (HttpWebRequest)WebRequest.Create(URI);
request.ProtocolVersion = HttpVersion.Version11;
}
else {//http
request = (HttpWebRequest)WebRequest.Create(URI);
}
request.AddRange(Form.restartPos[ThreadID], Form.startPos[ThreadID] + Form.fileSize[ThreadID]);//seek
stream = request.GetResponse().GetResponseStream();
readSize = stream.Read(buffer, 0, _bufferSize);
while (!Form.isPause && readSize > 0)
{
Handle(DownloadState.Downloading);
fileStream.Write(buffer, 0, readSize);
Form.hasReceived[ThreadID] += readSize;
readSize = stream.Read(buffer, 0, _bufferSize);
//Thread.Sleep(100);//下载优化
}
Form.restartPos[ThreadID] = Form.startPos[ThreadID] + Form.hasReceived[ThreadID];
stream.Close();
}
catch (Exception ex)
{
//Log.LogDebug.PrintError(ex.Message);
break;
}
}
}
if (Form.hasReceived[ThreadID] >= Form.fileSize[ThreadID] + 1)
{
break;
}
}
Form.threadIsEnd[ThreadID] = true;
//Log.LogDebug.Print(" 线程[" + ThreadID.ToString() + "] 结束");
}
//线程回调
private void Handle(DownloadState state)
{
int tempValue = 0;
for (int i = 0; i < Form.threadNum; i++)
{
tempValue += Form.hasReceived[i];
}
Callback?.Invoke(state, ((float)tempValue / Form.totalSize));
}
}
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public struct DownUnit //下载单元
{
public string downUrl; //下载地址
public string downTempPath; //临时地址
public string downSavePath; //保存地址
public int RetryTimes; //重试次数
};
public class DownLoadForm
{
// 定义并启动线程数组
System.Threading.Thread[] threads = null;
HttpMultiThreadDownload[] httpDownloads = null;
//下载文件URI
public string SourceURI = null;
//保存文件名
public string TargetFileName = null;
//是否暂停
public volatile bool isPause = false;
//是否首次下载
public bool first = true;
//线程数
public int threadNum = 4;
//每个线程接收文件的大小
public int[] fileSize { get; set; }
//每个线程已经接收文件的大小
public int[] hasReceived { get; set; }
//每个线程接收文件的文件名
public string[] fileNames { get; set; }
//每个线程接收文件的起始位置
public int[] startPos { get; set; }
//每个线程继续接收文件的位置
public int[] restartPos { get; set; }
//每个线程结束标志
public bool[] threadIsEnd { get; set; }
//文件合并标志
public bool canMerge { get; set; }
//文件总数
public long totalSize = 0;
//下载回调
Action<DownloadState, float> Callback = null;
public DownLoadForm()
{
}
//点击下载按钮
public void DownloadFile(DownUnit unit, Action<DownloadState, float> callback)
{
Callback = callback;
isPause = false;
SourceURI = unit.downUrl;
TargetFileName = unit.downSavePath;
HttpWebRequest request;
totalSize = 0;
try
{
if (first)
{
//Print(DateTime.Now.ToString() + " 开始下载 " + SourceURI);
if (SourceURI.StartsWith("https", StringComparison.OrdinalIgnoreCase))//https
{
ServicePointManager.ServerCertificateValidationCallback
= new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
=> { return true; });
request = (HttpWebRequest)WebRequest.Create(SourceURI);
request.ProtocolVersion = HttpVersion.Version11;
}
else {//http
request = (HttpWebRequest)WebRequest.Create(SourceURI);
}
totalSize = request.GetResponse().ContentLength;
//Print("文件字节数:" + totalSize);
request.Abort();
Init(totalSize);
threads = new System.Threading.Thread[threadNum];
httpDownloads = new HttpMultiThreadDownload[threadNum];
for (int i = 0; i < threadNum; i++)
{
httpDownloads[i] = new HttpMultiThreadDownload(this, i, callback);
threads[i] = new System.Threading.Thread(new System.Threading.ThreadStart(httpDownloads[i].Receive));
threads[i].Start();
}
System.Threading.Thread merge = new System.Threading.Thread(new System.Threading.ThreadStart(MergeFile));
merge.Start();
}
else
{
//Print(DateTime.Now.ToString() + " 继续下载");
}
}
catch (Exception ex)
{
//Debug.LogError(ex.Message);
}
}
//分配线程:每个线程平均分配文件大小,剩余部分由最后一个线程完成
private void Init(long totalSize)
{
fileNames = new string[threadNum];
startPos = new int[threadNum];
restartPos = new int[threadNum];
fileSize = new int[threadNum];
hasReceived = new int[threadNum];
threadIsEnd = new bool[threadNum];
int size = (int)totalSize / threadNum;
int endSize = size + (int)totalSize % threadNum;
for (int i = 0; i < threadNum; i++)
{
fileNames[i] = TargetFileName + i.ToString() + ".dat";
startPos[i] = size * i;
restartPos[i] = size * i;
fileSize[i] = (i < threadNum - 1) ? (size - 1) : (endSize - 1);
hasReceived[i] = 0;
threadIsEnd[i] = false;
}
}
//合并文件
public void MergeFile()
{
while (true)
{
canMerge = true;
for (int i = 0; i < threadNum; i++)
{
//若有未结束线程,则等待
if (!threadIsEnd[i])
{
canMerge = false;
System.Threading.Thread.Sleep(100);
break;
}
}
if (canMerge == true)
break;
}
int bufferSize = 1024 * 16;
int readSize;
byte[] bytes = new byte[bufferSize];
FileStream fileStream = new FileStream(TargetFileName, FileMode.OpenOrCreate);
FileStream tempStream = null;
for (int k = 0; k < threadNum; k++)
{
tempStream = new FileStream(fileNames[k], FileMode.Open);
while (true)
{
readSize = tempStream.Read(bytes, 0, bufferSize);
if (readSize > 0)
fileStream.Write(bytes, 0, readSize);
else
break;
}
tempStream.Close();
//删除临时文件
File.Delete(fileNames[k]);
}
fileStream.Close();
Callback?.Invoke(DownloadState.DownloadSucceed, 1);
//Print(DateTime.Now.ToString() + " 下载完成, 保存于 " + TargetFileName);
}
public void Dispose()
{
isPause = true;
first = false;
foreach (var item in threads)
{
if (item != null && item.IsAlive)
{
item.Abort();
}
}
}
public void Stop()
{
isPause = true;
first = false;
}
public void ReStart()
{
isPause = false;
first = false;
}
}