下载管理器 – 限制下载速度

我需要为我的文件下载器应用程序实现下载速率限制,并且我已经查看了CodeProject中的ThrottledStream类,但这在我的情况下不起作用,因为我必须能够在下载期间更改限制,而不是刚刚开始。 这是我在后台线程中使用的下载方法的一部分:

 webResponse = (HttpWebResponse)webRequest.GetResponse(); responseStream = webResponse.GetResponseStream(); responseStream.ReadTimeout = 5000; downloadCache = new MemoryStream(this.MaxCacheSize); byte[] downloadBuffer = new byte[this.BufferSize]; int bytesSize = 0; CachedSize = 0; int receivedBufferCount = 0; while (true) { bytesSize = responseStream.Read(downloadBuffer, 0, downloadBuffer.Length); if (this.Status != DownloadStatus.Downloading || bytesSize == 0 || this.MaxCacheSize < CachedSize + bytesSize) { WriteCacheToFile(downloadCache, CachedSize); this.DownloadedSize += CachedSize; downloadCache.Seek(0, SeekOrigin.Begin); CachedSize = 0; if (this.Status != DownloadStatus.Downloading || bytesSize == 0) break; } downloadCache.Write(downloadBuffer, 0, bytesSize); CachedSize += bytesSize; receivedBufferCount++; if (receivedBufferCount == this.BufferCountPerNotification) { this.RaiseDownloadProgressChanged(); receivedBufferCount = 0; } } 

我也见过人们使用Thread.Sleep()或Thread.Wait(),但这是个好主意吗? 你有什么建议我可以在这个while循环中做到这一点吗?

我用这个代码从服务器下载文件可能对你有帮助…

  private bool DownLoadFile(string pstrFileName, string pstrFilePath, long plngFileSize) { try { string strNewFileSize = CalcFileSize(plngFileSize); int numIterations = 0; // this is used with a modulus of the sampleInterval to check if the chunk size should be adjusted. it is started at 1 so that the first check will be skipped because it may involve an initial delay in connecting to the web service Offset = 0; long webConfigSetting = this.mobjService.GetMaxRequestLength(); this.MaxRequestLength = Math.Max(1, (webConfigSetting * 1024) - (2 * 1024)); // set the max buffer size to slightly less than the request length to allow for SOAP message headers etc. if (File.Exists(pstrFilePath)) { Offset = new FileInfo(pstrFilePath).Length; if (Offset == plngFileSize) Offset = 0; //File.Delete(pstrFilePath); } if (Offset == 0 && !File.Exists(pstrFilePath)) // create a new empty file File.Create(pstrFilePath).Close(); // open a file stream for the file we will write to in the start-up folder lblFileName.Text = pstrFileName.Substring(0, pstrFileName.LastIndexOf(".")).Replace("&", "&&"); using (FileStream fs = new FileStream(pstrFilePath, FileMode.OpenOrCreate, FileAccess.Write)) { pbrSummary.Maximum = (int)plngFileSize; fs.Seek(Offset, SeekOrigin.Begin); // download the chunks from the web service one by one, until all the bytes have been read, meaning the entire file has been downloaded. while (Offset < plngFileSize) { int currentIntervalMod = numIterations % this.ChunkSizeSampleInterval; if (currentIntervalMod == 0) StartTime = DateTime.Now; // used to calculate the time taken to transfer the first 5 chunks else if (currentIntervalMod == 1) CalcAndSetChunkSize(plngFileSize); try { // although the DownloadChunk returns a byte[], it is actually sent using MTOM because of the configuration settings. byte[] Buffer = mobjService.DownloadChunk(pstrFileName, Offset, ChunkSize); fs.Write(Buffer, 0, Buffer.Length); Offset += Buffer.Length; // save the offset position for resume } catch (Exception ex) { if (ex.Message.Contains("File not found") || NumRetries++ >= MaxRetries) // too many retries, bail out { fs.Close(); return false; //throw new Exception("Error occurred during upload, too many retries.\r\n" + ex.Message); } } numIterations++; //----------------------- Code Commented ------------------------ //lblDownload.Text = CalcFileSize(Offset) + " of " + strNewFileSize; //lblRate.Text = CalcFileSize(ChunkSize)+"/sec"; ////pbrSummary.Value = (int)Offset; ////if ((int)Offset <= pbrSummary.Maximum) //// pbrSummary.Value = (int)Offset; ////else //// pbrSummary.Value = pbrSummary.Maximum; //------------------------------------------------------------------ } } return true; } catch (Exception Exc) { throw (Exc); } } private void CalcAndSetChunkSize(long plngFileSize) { /* chunk size calculation is defined as follows * in the examples below, the preferred transfer time is 1500ms, taking one sample. * * Example 1 Example 2 * Initial size = 16384 bytes (16k) 16384 * Transfer time for 1 chunk = 800ms 2000 ms * Average throughput / ms = 16384b / 800ms = 20.48 b/ms 16384 / 2000 = 8.192 b/ms * How many bytes in 1500ms? = 20.48 * 1500 = 30720 bytes 8.192 * 1500 = 12228 bytes * New chunksize = 30720 bytes (speed up) 12228 bytes (slow down from original chunk size) */ double transferTime = DateTime.Now.Subtract(this.StartTime).TotalMilliseconds; double averageBytesPerMilliSec = this.ChunkSize / transferTime; double preferredChunkSize = averageBytesPerMilliSec * this.PreferredTransferDuration; this.ChunkSize = (int)Math.Min(this.MaxRequestLength, Math.Max(4 * 1024, preferredChunkSize)) * 10; // set the chunk size so that it takes 1500ms per chunk (estimate), not less than 4Kb and not greater than 4mb // (note 4096Kb sometimes causes problems, probably due to the IIS max request size limit, choosing a slightly smaller max size of 4 million bytes seems to work nicely) //string statusMessage = String.Format("Chunk size: {0}{1}", CalcFileSize(this.ChunkSize), (this.ChunkSize == this.MaxRequestLength) ? " (max)" : ""); }