我运行以下代码时,发现在默认超时时间100s后,出现一堆
System.WebException: 操作超时
的错误。加追踪后发现,ID为2、4、6等的线程均出错,而0 1 3 5等则正常完成下载。代码如下(无追踪版):
public class ThreadDownload {
private volatile Array<bool> DownloadEndFlag;
private volatile Array<Array<byte>> DownloadBuffer;
private long DownloadEndBytes = 0;
public ThreadDownload(string URL,uint Threads = 32,string Path = null) {
HttpsStarts();
Path = Path==null ? GetURLFileName(URL) : Path;
Threads += 1;
DownloadEndFlag = new ((int)Threads);
DownloadBuffer = new ((int)Threads);
long Length = GetFileLength(URL);
long ThreadDownloadLong = (Length - Length % (Threads - 1)) / (Threads - 1);
if (CanAddRange(URL)) {
Thread PushThread = new (info => {
PushInfo Info = (PushInfo)info;
if (File.Exists(Info.Path)) {
File.Delete(Info.Path);
}
uint DownloadEndKey = 0;
for (;DownloadEndKey < Info.Threads;) {
if (DownloadEndFlag[(int)DownloadEndKey]) {
using (var write = new FileStream(Path,FileMode.Append,FileAccess.Write)) {
write.Write(DownloadBuffer[(int)DownloadEndKey],0,DownloadBuffer[(int)DownloadEndKey].Length);
}
++DownloadEndKey;
} else {
Thread.Sleep(150);
}
}
});
Array<Thread> DownThread = new Thread[Threads];
PushThread.Start(new PushInfo(Length,Threads,Path));
for (int i = 0;i < DownThread.Length;++i) {
DownloadInfo t = new DownloadInfo(
ThreadDownloadLong*i,
i==DownThread.Length-1 ? Length : ThreadDownloadLong*(i+1),
(uint)i,
URL);
DownThread[i] = new Thread(info => {
DownloadInfo Info = (DownloadInfo)info;
DownloadBuffer[(int)Info.ID] = new ((int)(Info.End-Info.Start+1));
var t = (HttpWebRequest)HttpWebRequest.Create(Info.URL);
t.AddRange(Info.Start,Info.End);
var t3 = t.GetResponse();//报错位置
var t2 = t3.GetResponseStream();
ReadAllData(t2,DownloadBuffer[(int)Info.ID],(uint)(Info.End-Info.Start+1));
t3.Close();
DownloadEndFlag[(int)Info.ID] = true;
});
DownThread[i].Start(t);
}
PushThread.Join();
} else {
new Download(URL,Path);
}
}
private struct DownloadInfo {
public long Start;
public long End;
public uint ID;
public string URL;
public DownloadInfo(long s,long e,uint i,string u) {
Start = s;
End = e;
ID = i;
URL = u;
}
}
private struct PushInfo {
public long Length;
public uint Threads;
public string Path;
public PushInfo(long l,uint t,string p) {
Length = l;
Threads = t;
Path = p;
}
}
}
internal static class DownloadHelperClass {
public static bool CanAddRange(string URL) {
var readreturntmp1 = ((HttpWebRequest)WebRequest.Create(URL));
readreturntmp1.AddRange(0,1);
var ret = ((HttpWebResponse)readreturntmp1.GetResponse()).Headers;
for (int i = 0;i < ret.AllKeys.Length;++i) {
if (ret.AllKeys[i].Equals("Accept-Ranges") && ret[i].Equals("bytes")) {
return true;
} else if (ret.AllKeys[i].Equals("Accept-Ranges") && ret[i].Equals("none")) {
return false;
}
}
return false;
}
public static void HttpsStarts() {
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.SystemDefault | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
}
public static string GetURLFileName(string URL) {
var t = new Uri(URL).Segments;
return t[t.Length-1];
}
public static void ReadAllData(Stream read,byte[] array,uint DataLong) {
array = new byte[DataLong];
for (uint key = 0;key < DataLong;) {
key += (uint)read.Read(array,(int)key,(int)(DataLong-key));
}
}
public static long GetFileLength(string URL) {
long length = 0;
var req = (HttpWebRequest)WebRequest.Create(URL);
req.Method = "HEAD";
var res = (HttpWebResponse)req.GetResponse();
if (res.StatusCode == HttpStatusCode.OK) {
length = res.ContentLength;
}
res.Close();
return length;
}
}