Повторное использование HttpClient для многочастной загрузки - PullRequest
0 голосов
/ 03 мая 2018

Я повторно использую HttpClient для всех своих задач загрузки, потому что я всегда видел в SO, что мне следует повторно использовать httpclient для всего. Но я получаю это исключение Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The request was aborted: The request was canceled.

Это то, что я сделал до сих пор.
1. Создайте новый экземпляр HttpClient для каждой задачи загрузки (работал, но не повторно использовал httpclient)
2. Уменьшить количество заданий до 2 (работает, все, что выше 2, вызывает исключение)
3. Удалите HttpCompletionOption.ResponseHeadersRead из сообщения запроса (работает, но для начала загрузки требуется слишком много времени, я думаю, что он продолжает читать все файлы перед запуском потока)
4. Сделать HttpClient тайм-аут до бесконечности (не работает)
5. Используйте метод HttpContent.ReadAsStreamAsync и установите время ожидания чтения на бесконечное (не работает)

Вот код

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Run(() => new Downloader().Download(
                "https://ia800703.us.archive.org/34/items/1mbFile/1mb.mp4",
                "1mb.mp4"
            )).Wait();
        }
    }

    public class Downloader
    {
        HttpClient httpClient;

        public Downloader()
        {
            httpClient = new HttpClient();
        }

        public async Task Download(string url, string saveAs)
        {
            var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url), HttpCompletionOption.ResponseHeadersRead);
            var parallelDownloadSuported = response.Headers.AcceptRanges.Contains("bytes");
            var contentLength = response.Content.Headers.ContentLength ?? 0;

            if (parallelDownloadSuported)
            {
                const double numberOfParts = 5.0;
                var tasks = new List<Task>();
                var partSize = (long)Math.Ceiling(contentLength / numberOfParts);

                File.Create(saveAs).Dispose();

                for (var i = 0; i < numberOfParts; i++)
                {
                    var start = i * partSize + Math.Min(1, i);
                    var end = Math.Min((i + 1) * partSize, contentLength);

                    tasks.Add(
                        Task.Run(() => DownloadPart(url, saveAs, start, end))
                        );
                }

                await Task.WhenAll(tasks);
            }
        }

        private async void DownloadPart(string url, string saveAs, long start, long end)
        {
            using (var fileStream = new FileStream(saveAs, FileMode.Open, FileAccess.Write, FileShare.Write, 1024, true))
            {
                var message = new HttpRequestMessage(HttpMethod.Get, url);
                message.Headers.Add("Range", string.Format("bytes={0}-{1}", start, end));

                fileStream.Position = start;
                await httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).Result.Content.CopyToAsync(fileStream);
            }
        }
    }
}

коды от: здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...