制作一个httpclient静态下载器
Make a httpclient static downloader
我真的需要帮助。有人可以帮我把这些代码设为静态吗?
我在这里的某个地方得到了这个并且我添加了一些代码。
但是我注意到下载过程很慢,因为没有使用 httpclient 作为单个实例。
我想让它成为静态的,这样我就可以将 httpclient 和处理程序作为所有请求的单个实例。
我试图将其设置为静态但我失败了,因为我无法从我的主要 gui 表单触发进度百分比和总字节数。
这是下载器的完整源代码。
class Downloader : IDisposable
{
private const string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36";
private string DownloadUrl { get; set; }
private string OutputFilePath { get; set; }
private HttpClientHandler handler;
private HttpClient client;
public delegate void ProgressChangedHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
public delegate void ProgressChangedHandler2(double? progressPercentage);
public event ProgressChangedHandler ProgressChanged; //for label progress
public Downloader(string downloadUrl, string outputFilePath)
{
DownloadUrl = downloadUrl;
OutputFilePath = outputFilePath;
}
public async Task StartDownload(CancellationToken token)
{
handler = new HttpClientHandler()
{
Proxy = null,
UseProxy = false,
UseCookies = false,
//SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
//ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
};
client = new HttpClient(handler);
Uri uri = new Uri(DownloadUrl, UriKind.Absolute);
SetConnection(uri);
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
{
request.RequestUri = uri;
request.Headers.UserAgent.ParseAdd(UserAgent);
using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token))
{
await DownloadFileFromHttpResponseMessage(response, token);
}
}
}
private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response, CancellationToken token)
{
response.EnsureSuccessStatusCode();
using (var contentStream = await response.Content.ReadAsStreamAsync())
{
long? totalBytes = response.Content.Headers.ContentLength;
long totalBytesRead = 0L;
long readCount = 0L;
byte[] buffer = new byte[4096];
bool isMoreToRead = true;
using (var fileStream = new FileStream(OutputFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
do
{
int bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, token);
if (bytesRead == 0)
{
isMoreToRead = false;
TriggerProgressChanged(totalBytes, totalBytesRead);
continue;
}
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
readCount += 1;
if (readCount % 10 == 0)
{
TriggerProgressChanged(totalBytes, totalBytesRead);
}
}
while (isMoreToRead);
}
TriggerProgressChanged(totalBytes, totalBytesRead);
}
}
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
{
if (ProgressChanged == null)
return;
double? progressPercentage = null;
if (totalDownloadSize.HasValue)
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage);
}
private void SetConnection(Uri uri)
{
var sp = ServicePointManager.FindServicePoint(uri);
sp.ConnectionLimit = 20; //default 2 //The number of connections per end point.
sp.UseNagleAlgorithm = false; //Nagle’s algorithm is a means of improving the efficiency of TCP/IP networks by reducing the number of packets that need to be sent over the network
sp.Expect100Continue = false; //save bandwidth before sending huge object for post and put request to ensure remote end point is up and running.
sp.ConnectionLeaseTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;//60 * 1000; // 1 minute
}
public void Dispose()
{
client?.Dispose();
}
}
这是来自我的 gui 的代码
using (var client = new Downloader(url, outputFilePath))
{
client.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) =>
{
sw.Start();
if (tryAbort) { PauseOrResumeProcess(); }
PB.Value = Convert.ToInt32(progressPercentage);
lvi.SubItems[2].Text = ($"{progressPercentage}%");
lvi.SubItems[3].Text = ($"{ Utils.FormatFileSize(totalBytesDownloaded)} of { Utils.FormatFileSize(totalFileSize.Value)}");
};
await client.StartDownload(ct);
}
最好将 HttpClient 添加到应用程序的范围内,这意味着每个线程只有一个 HTTP 客户端实例。
只需将 services.AddScoped<HttpClient>();
添加到您的 ConfigureServices(IServiceCollection services)
启动 class 并在那里进行配置。然后:
public Downloader(string downloadUrl, string outputFilePath, HttpClient client)
{
DownloadUrl = downloadUrl;
OutputFilePath = outputFilePath;
this.client = client;
}
更新:
好的,这就是我尝试过的并且有效。
我刚刚也删除了 IDisposable 并且只将客户端和处理程序更改为静态并且我获得了最大下载速度。
private static readonly HttpClientHandler handler = new HttpClientHandler()
{
Proxy = null,
UseProxy = false
};
private static readonly HttpClient client = new HttpClient(handler);
我真的需要帮助。有人可以帮我把这些代码设为静态吗? 我在这里的某个地方得到了这个并且我添加了一些代码。 但是我注意到下载过程很慢,因为没有使用 httpclient 作为单个实例。
我想让它成为静态的,这样我就可以将 httpclient 和处理程序作为所有请求的单个实例。
我试图将其设置为静态但我失败了,因为我无法从我的主要 gui 表单触发进度百分比和总字节数。
这是下载器的完整源代码。
class Downloader : IDisposable
{
private const string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36";
private string DownloadUrl { get; set; }
private string OutputFilePath { get; set; }
private HttpClientHandler handler;
private HttpClient client;
public delegate void ProgressChangedHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
public delegate void ProgressChangedHandler2(double? progressPercentage);
public event ProgressChangedHandler ProgressChanged; //for label progress
public Downloader(string downloadUrl, string outputFilePath)
{
DownloadUrl = downloadUrl;
OutputFilePath = outputFilePath;
}
public async Task StartDownload(CancellationToken token)
{
handler = new HttpClientHandler()
{
Proxy = null,
UseProxy = false,
UseCookies = false,
//SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
//ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
};
client = new HttpClient(handler);
Uri uri = new Uri(DownloadUrl, UriKind.Absolute);
SetConnection(uri);
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
{
request.RequestUri = uri;
request.Headers.UserAgent.ParseAdd(UserAgent);
using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token))
{
await DownloadFileFromHttpResponseMessage(response, token);
}
}
}
private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response, CancellationToken token)
{
response.EnsureSuccessStatusCode();
using (var contentStream = await response.Content.ReadAsStreamAsync())
{
long? totalBytes = response.Content.Headers.ContentLength;
long totalBytesRead = 0L;
long readCount = 0L;
byte[] buffer = new byte[4096];
bool isMoreToRead = true;
using (var fileStream = new FileStream(OutputFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
do
{
int bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, token);
if (bytesRead == 0)
{
isMoreToRead = false;
TriggerProgressChanged(totalBytes, totalBytesRead);
continue;
}
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
readCount += 1;
if (readCount % 10 == 0)
{
TriggerProgressChanged(totalBytes, totalBytesRead);
}
}
while (isMoreToRead);
}
TriggerProgressChanged(totalBytes, totalBytesRead);
}
}
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
{
if (ProgressChanged == null)
return;
double? progressPercentage = null;
if (totalDownloadSize.HasValue)
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage);
}
private void SetConnection(Uri uri)
{
var sp = ServicePointManager.FindServicePoint(uri);
sp.ConnectionLimit = 20; //default 2 //The number of connections per end point.
sp.UseNagleAlgorithm = false; //Nagle’s algorithm is a means of improving the efficiency of TCP/IP networks by reducing the number of packets that need to be sent over the network
sp.Expect100Continue = false; //save bandwidth before sending huge object for post and put request to ensure remote end point is up and running.
sp.ConnectionLeaseTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;//60 * 1000; // 1 minute
}
public void Dispose()
{
client?.Dispose();
}
}
这是来自我的 gui 的代码
using (var client = new Downloader(url, outputFilePath))
{
client.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) =>
{
sw.Start();
if (tryAbort) { PauseOrResumeProcess(); }
PB.Value = Convert.ToInt32(progressPercentage);
lvi.SubItems[2].Text = ($"{progressPercentage}%");
lvi.SubItems[3].Text = ($"{ Utils.FormatFileSize(totalBytesDownloaded)} of { Utils.FormatFileSize(totalFileSize.Value)}");
};
await client.StartDownload(ct);
}
最好将 HttpClient 添加到应用程序的范围内,这意味着每个线程只有一个 HTTP 客户端实例。
只需将 services.AddScoped<HttpClient>();
添加到您的 ConfigureServices(IServiceCollection services)
启动 class 并在那里进行配置。然后:
public Downloader(string downloadUrl, string outputFilePath, HttpClient client)
{
DownloadUrl = downloadUrl;
OutputFilePath = outputFilePath;
this.client = client;
}
更新: 好的,这就是我尝试过的并且有效。 我刚刚也删除了 IDisposable 并且只将客户端和处理程序更改为静态并且我获得了最大下载速度。
private static readonly HttpClientHandler handler = new HttpClientHandler()
{
Proxy = null,
UseProxy = false
};
private static readonly HttpClient client = new HttpClient(handler);