下载100个文件后线程似乎卡住了

时间:2015-11-27 23:54:43

标签: c# multithreading http

我刚写了一个下载管理器来并行下载多个文件。但我有这个脚本的1个问题,我找不到答案。经过很多文件(100会做)。有时线程只是没有完成它的工作。它不会触发超时,也不会触发我放置的异常或控制台日志。当我检查需要下载所有文件的文件夹时,我在那里看到一个不完整的文件,它正被应用程序使用(我知道这是因为我关闭应用程序之前无法删除文件)。我希望有人会在我的剧本中看到问题。

//Download complete delegate
public delegate void DownloadCompleteHandler(DownloadableObject source, DownloadCompletedEventArgs e);

//Download complete event args
public class DownloadCompletedEventArgs : EventArgs
{
    private string EventInfo;
    public DownloadCompletedEventArgs(string text)
    {
        EventInfo = text;
    }
    public string GetInfo()
    {
        return EventInfo;
    }
}

class DownloadManager
{
    //Downloadcomplete Handler
    public event DownloadCompleteHandler DownloadComplete;

    //The amount of downloads that can run in parallel
    public int parallelDownloads = 1;

    //All the downloads in a list
    public List<DownloadableObject> downloads = new List<DownloadableObject>();

    public DownloadManager(int parallelDownloads = 1)
    {
        this.parallelDownloads = parallelDownloads;
    }

    //This adds a download to the list.
    public void addDownload(string url, string saveLocation)
    {
        DownloadableObject dl = new DownloadableObject() { url = url, saveLocation = saveLocation };
        downloads.Add(dl);
    }

    //This starts the parallel downloader
    public void startParallelDownloads()
    {
        for(int i = 0; i < parallelDownloads; i++)
        {
            startDownload();
        }
    }

    //This starts a single download Async
    private void startDownload()
    {
        //Check if the downloads list contains anything
        if(downloads.Any())
        {
            //Get the first download from the list and remove it so it doesn't get downloaded again.
            DownloadableObject currentDl = downloads[0];
            downloads.RemoveAt(0);

            //Setup a webrequest.
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(currentDl.url);
            webRequest.Method = "GET";
            webRequest.Timeout = 4000;
            currentDl.webRequest = webRequest;
            IAsyncResult result = webRequest.BeginGetResponse(new AsyncCallback(downloadResponse), currentDl);

            //This handles the timeout response
            ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(timeoutCallback), currentDl, currentDl.webRequest.Timeout, true);
        } else
        {
            //Called when a Thread is done downloading. This should be called when the download list is empty
            Console.WriteLine("THREAD DONE!");
        }
    }

    //This is the callback when a timeout occurs
    private void timeoutCallback(object state, bool timedOut)
    {
        if(timedOut)
        {
            //Get the timedout request
            HttpWebRequest request = ((DownloadableObject)state).webRequest;
            if(request != null)
            {
                Console.WriteLine("Too Bad!");
                //And abort it
                request.Abort();

                //Set the webrequest in the downloadable object to null and add it to the download list again so it will be downloaded again
                ((DownloadableObject)state).webRequest = null;
                downloads.Add(((DownloadableObject)state));
                //Refire the thread.
                startDownload();
            }
        }
    }

    private void downloadResponse(IAsyncResult asyncResult)
    {
        int received = 0;
        //Get the current download from the asyncResult.
        DownloadableObject currentDl = (DownloadableObject)asyncResult.AsyncState;

        try
        {
            using (HttpWebResponse webResponse = (HttpWebResponse)currentDl.webRequest.EndGetResponse(asyncResult))
            {
                byte[] buffer = new byte[1024];

                //Creates a file in the correct location.
                FileStream fileStream = File.OpenWrite(currentDl.saveLocation);
                using (Stream input = webResponse.GetResponseStream())
                {
                    //Write data to the buffer.
                    int size = input.Read(buffer, 0, buffer.Length);
                    while (size > 0)
                    {
                        fileStream.Write(buffer, 0, size);
                        received += size;

                        size = input.Read(buffer, 0, buffer.Length);
                    }
                }

                //Write data to the file and close it.
                fileStream.Flush();
                fileStream.Close();
                //Call the download complete event
                DownloadComplete(currentDl, new DownloadCompletedEventArgs("Download completed"));

                //refire the Thread again.
                startDownload();
            }
        }
        catch (WebException e)
        {

        }
    }
}

//A downloadable object.
public class DownloadableObject
{
    //Url to file to download
    public string url { get; set; }
    //Location where to save the file
    public string saveLocation { get; set; }
    //The webrequest that is assigned to this download. This will be null when the download list is filled.
    public HttpWebRequest webRequest { get; set; }
}

0 个答案:

没有答案