【问题标题】:Download manager - limit download speed [duplicate]下载管理器 - 限制下载速度 [重复]
【发布时间】:2016-07-02 09:11:00
【问题描述】:

我需要为我的文件下载器应用程序实现下载速率限制,我查看了 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循环中做到这一点吗?

【问题讨论】:

    标签: c# .net stream download download-manager


    【解决方案1】:

    我已经使用此代码从服务器下载文件可能对您有帮助...

       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)" : "");
        }
    

    【讨论】:

    • 我需要看看 CalcFileSize 方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 2013-03-30
    • 2015-07-11
    • 2011-04-29
    • 2016-04-20
    • 1970-01-01
    • 2018-04-25
    相关资源
    最近更新 更多