WinForm客户端限速下载(C#限速下载)
最近由于工作需要,需要开发一个能把服务器上的文件批量下载下来本地保存,关键是要实现限速下载,如果全速下载会影响服务器上的带宽流量。本来我最开始的想法是在服务器端开发一个可以从源头就限速下载的Api端口,可是找了半天没有相关的实现代码,后来好不容易找到一个,却只能只能在WebForm的HttpResponse上实现,我用的是webApi的HttpResponseMessage实现不了把流文件一点一点输出。(可能是我对相关协议还不清楚,所以把参考链接给出,如果有知道怎么在WebApi框架服务器端限速下载的童鞋,麻烦告诉我一下:https://www.cnblogs.com/ghd258/articles/260236.html)
后来没办法,把思路改为直接在下载的客户端限制下载速度,主体思路就是每下载N字节后就计算平均下载速度,如果平均下载速度快了,就暂停下载,通过拉长下载时间来实现降低平均下载速度。下面贴出主要核心的下载代码:
欢迎批评指正,写的比较匆忙!
1 /// <summary> 2 /// 下载并保存文件 3 /// </summary> 4 /// <param name="waveID">主键</param> 5 /// <param name="saveName">文件名</param> 8 /// <param name="folderName">文件夹名称</param> 9 /// <param name="speed">限速</param> 10 /// <param name="callBackMethod">回调</param> 11 /// <returns></returns> 12 public int DownloadAndSaveAs(string waveID, string saveName, string folderName, int speed, SetTextCallBack callBackMethod) 13 { 14 if (string.IsNullOrWhiteSpace(waveID)) 15 return -1; 16 17 using (WebClient webClient = new WebClient()) 18 { 19 try 20 { 21 string savePath = "C:\\"+ folderName+ "\\"; 22 if (!Directory.Exists(savePath)) 23 { 24 Directory.CreateDirectory(savePath); 25 } 26 using (FileStream fs = new FileStream(savePath + saveName, FileMode.Create, FileAccess.Write)) 27 { 28 try 29 { 30 string url =string.Format( "Http://www.文件下载路径.com?waveID={0}",waveID); 31 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 32 33 using (var response = (HttpWebResponse)request.GetResponse()) 34 using (var stream = response.GetResponseStream()) 35 { 36 int blockSize = 4096;//每次读取的字节数,不固定 37 byte[] buffer = new byte[blockSize]; 38 int read = 0;//每次读取后返回的下一次 的坐标位置,当没有数据时是-1 39 long total_read = 0;//已经读取到的字节数总和 40 DateTime begin = DateTime.Now; 41 42 while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) 43 { 44 total_read += blockSize; 45 double totalSeconds=DateTime.Now.Subtract(begin).TotalSeconds; 46 double byteper = total_read / totalSeconds;//[字节总数]除以[所花时间总秒数]=每秒获取的字节数 47 48 if (double.IsInfinity(byteper)) 49 { 50 //排除byteper正无穷的情况 51 fs.Write(buffer, 0, buffer.Length); 52 continue; 53 } 54 else 55 { 56 double speedPer = byteper / 1024;//单位转换得到千字节 57 if (speedPer >= speed)//speed为我们设置的限速字段,单位kb 58 { 59 //下面的逻辑是通过:现实速度-限速=超速部分,通过超速部分计算要让线程休眠时长。 60 double tempData = speedPer - speed; 61 if (tempData < 1) tempData = 1; 62 int sleepMS = Convert.ToInt32(tempData * (1000 / speed) + 100);//1000除以速度得到“每KB消耗的毫秒数”,100是一个自定义值,更好的限制下载速度 63 if (sleepMS > 1000) 64 { 65 sleepMS = 1000;//有时下载峰值会超大,导致休眠很长,所以强制设为最多休眠一秒。 66 } 67 else 68 { 69 if (total_read % 112 == 0)//取模只用于降低重写文本框的频率 70 { 71 if (callBackMethod != null) 72 { 73 callBackMethod(string.Format("下载速度:{0}KB/s,休眠周期:{1} ms", speedPer.ToString("F"), sleepMS)); 74 } 75 } 76 } 77 System.Threading.Thread.Sleep(sleepMS); // 休眠实现限速 78 } 79 else 80 { 81 if (total_read % 198 == 0) 82 { 83 if (callBackMethod != null) 84 { 85 callBackMethod(string.Format("下载速度:{0}KB/s,休眠周期:{1} ms", speedPer.ToString("F"), 0)); 86 } 87 } 88 89 } 90 fs.Write(buffer, 0, buffer.Length); 91 } 92 } 93 } 94 return 1; 95 } 96 catch (Exception e) 97 { 98 return -1; 99 } 100 } 101 } 102 catch (Exception ex) 103 { 104 return -1; 105 } 106 } 107 }
本文参考了,但做了优化:http://blog.useasp.net/archive/2016/03/10/limit-download-speed-in-dotnet-httpwebresponse.aspx