Compare commits

...

2 Commits

Author SHA1 Message Date
2dust e1a5c360ac Optimize timeout logic, try fix
https://github.com/2dust/v2rayN/issues/9681
2026-07-06 11:49:54 +08:00
2dust 0c570fcb38 Add Legacy Protect Tip 2026-07-06 10:18:31 +08:00
10 changed files with 77 additions and 27 deletions
@@ -38,7 +38,7 @@ public static class ConnectionHandler
for (var i = 0; i < 2; i++) for (var i = 0; i < 2; i++)
{ {
responseTime = await GetRealPingTime(webProxy, 10); responseTime = await GetRealPingTime(webProxy);
if (responseTime > 0) if (responseTime > 0)
{ {
break; break;
@@ -66,7 +66,7 @@ public static class ConnectionHandler
/// <summary> /// <summary>
/// Measures response time by sending HTTP requests through proxy. /// Measures response time by sending HTTP requests through proxy.
/// </summary> /// </summary>
public static async Task<int> GetRealPingTime(IWebProxy? webProxy, int downloadTimeout) public static async Task<int> GetRealPingTime(IWebProxy? webProxy, int downloadTimeout = 9)
{ {
var url = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl; var url = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
var responseTime = -1; var responseTime = -1;
@@ -77,7 +77,8 @@ public static class ConnectionHandler
using var client = new HttpClient(new SocketsHttpHandler() using var client = new HttpClient(new SocketsHttpHandler()
{ {
Proxy = webProxy, Proxy = webProxy,
UseProxy = webProxy != null UseProxy = webProxy != null,
ConnectTimeout = TimeSpan.FromSeconds(3)
}); });
List<int> oneTime = []; List<int> oneTime = [];
+11 -5
View File
@@ -14,6 +14,8 @@ public class DownloaderHelper
return null; return null;
} }
var connectTimeout = Math.Clamp(timeout / 5, 2, 5);
Uri uri = new(url); Uri uri = new(url);
//Authorization Header //Authorization Header
var headers = new WebHeaderCollection(); var headers = new WebHeaderCollection();
@@ -30,7 +32,7 @@ public class DownloaderHelper
{ {
Headers = headers, Headers = headers,
UserAgent = userAgent, UserAgent = userAgent,
ConnectTimeout = timeout * 1000, ConnectTimeout = connectTimeout * 1000,
Proxy = webProxy Proxy = webProxy
} }
}; };
@@ -45,7 +47,9 @@ public class DownloaderHelper
}; };
using var cts = new CancellationTokenSource(); using var cts = new CancellationTokenSource();
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token); cts.CancelAfter(TimeSpan.FromSeconds(timeout));
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
using StreamReader reader = new(stream); using StreamReader reader = new(stream);
downloadOpt = null; downloadOpt = null;
@@ -60,13 +64,14 @@ public class DownloaderHelper
throw new ArgumentNullException(nameof(url)); throw new ArgumentNullException(nameof(url));
} }
var connectTimeout = Math.Clamp(timeout / 5, 2, 5);
var downloadOpt = new DownloadConfiguration() var downloadOpt = new DownloadConfiguration()
{ {
BlockTimeout = timeout * 1000, BlockTimeout = timeout * 1000,
MaxTryAgainOnFailure = 2, MaxTryAgainOnFailure = 2,
RequestConfiguration = RequestConfiguration =
{ {
ConnectTimeout= timeout * 1000, ConnectTimeout= connectTimeout * 1000,
Proxy = webProxy Proxy = webProxy
} }
}; };
@@ -116,7 +121,7 @@ public class DownloaderHelper
}; };
//progress.Report("......"); //progress.Report("......");
using var cts = new CancellationTokenSource(); using var cts = new CancellationTokenSource();
cts.CancelAfter(timeout * 1000); cts.CancelAfter(TimeSpan.FromSeconds(timeout));
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token); await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
downloadOpt = null; downloadOpt = null;
@@ -137,13 +142,14 @@ public class DownloaderHelper
File.Delete(fileName); File.Delete(fileName);
} }
var connectTimeout = Math.Clamp(timeout / 5, 2, 5);
var downloadOpt = new DownloadConfiguration() var downloadOpt = new DownloadConfiguration()
{ {
BlockTimeout = timeout * 1000, BlockTimeout = timeout * 1000,
MaxTryAgainOnFailure = 2, MaxTryAgainOnFailure = 2,
RequestConfiguration = RequestConfiguration =
{ {
ConnectTimeout= timeout * 1000, ConnectTimeout= connectTimeout * 1000,
Proxy = webProxy Proxy = webProxy
} }
}; };
+9
View File
@@ -3339,6 +3339,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 If enabled, use sing-box TUN; otherwise, use xray TUN. 的本地化字符串。
/// </summary>
public static string TbLegacyProtectTip {
get {
return ResourceManager.GetString("TbLegacyProtectTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Address (IPv4, IPv6) 的本地化字符串。 /// 查找类似 Address (IPv4, IPv6) 的本地化字符串。
/// </summary> /// </summary>
+3
View File
@@ -1812,4 +1812,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbGeckoPacketSize" xml:space="preserve"> <data name="TbGeckoPacketSize" xml:space="preserve">
<value>Gecko Packet Size (min/max)</value> <value>Gecko Packet Size (min/max)</value>
</data> </data>
<data name="TbLegacyProtectTip" xml:space="preserve">
<value>If enabled, use sing-box TUN; otherwise, use xray TUN.</value>
</data>
</root> </root>
@@ -1809,4 +1809,7 @@
<data name="TbGeckoPacketSize" xml:space="preserve"> <data name="TbGeckoPacketSize" xml:space="preserve">
<value>Gecko 包大小 (最小/最大)</value> <value>Gecko 包大小 (最小/最大)</value>
</data> </data>
<data name="TbLegacyProtectTip" xml:space="preserve">
<value>启用则使用 sing-box TUN ,否则使用 xray TUN</value>
</data>
</root> </root>
@@ -1794,4 +1794,7 @@
<data name="TbEnabletDnsViaProxy" xml:space="preserve"> <data name="TbEnabletDnsViaProxy" xml:space="preserve">
<value>DNS 透過 Bridge</value> <value>DNS 透過 Bridge</value>
</data> </data>
<data name="TbLegacyProtectTip" xml:space="preserve">
<value>啟用則使用 sing-box TUN ,否則使用 xray TUN</value>
</data>
</root> </root>
+17 -7
View File
@@ -109,9 +109,10 @@ public class DownloadService
/// </summary> /// </summary>
public async Task<string?> TryDownloadString(string url, IWebProxy? webProxy, string userAgent) public async Task<string?> TryDownloadString(string url, IWebProxy? webProxy, string userAgent)
{ {
var timeout = 15;
try try
{ {
var result1 = await DownloadStringAsync(url, webProxy, userAgent, 15); var result1 = await DownloadStringAsync(url, webProxy, userAgent, timeout);
if (result1.IsNotEmpty()) if (result1.IsNotEmpty())
{ {
return result1; return result1;
@@ -129,7 +130,7 @@ public class DownloadService
try try
{ {
var result2 = await DownloadStringViaDownloader(url, webProxy, userAgent, 15); var result2 = await DownloadStringViaDownloader(url, webProxy, userAgent, timeout);
if (result2.IsNotEmpty()) if (result2.IsNotEmpty())
{ {
return result2; return result2;
@@ -155,11 +156,18 @@ public class DownloadService
{ {
try try
{ {
var client = new HttpClient(new SocketsHttpHandler() var connectTimeout = Math.Clamp(timeout / 5, 2, 5);
var handler = new SocketsHttpHandler
{ {
Proxy = webProxy, Proxy = webProxy,
UseProxy = webProxy != null UseProxy = webProxy != null,
}); ConnectTimeout = TimeSpan.FromSeconds(connectTimeout)
};
using var client = new HttpClient(handler)
{
Timeout = Timeout.InfiniteTimeSpan
};
if (userAgent.IsNullOrEmpty()) if (userAgent.IsNullOrEmpty())
{ {
@@ -175,8 +183,9 @@ public class DownloadService
} }
using var cts = new CancellationTokenSource(); using var cts = new CancellationTokenSource();
var result = await client.GetStringAsync(url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token); cts.CancelAfter(TimeSpan.FromSeconds(timeout));
return result;
return await client.GetStringAsync(url, cts.Token);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -187,6 +196,7 @@ public class DownloadService
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
} }
} }
return null; return null;
} }
@@ -420,7 +420,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
private async Task<int> DoRealPing(ServerTestItem it) private async Task<int> DoRealPing(ServerTestItem it)
{ {
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
var responseTime = await ConnectionHandler.GetRealPingTime(webProxy, 10); var responseTime = await ConnectionHandler.GetRealPingTime(webProxy);
ProfileExManager.Instance.SetTestDelay(it.IndexId, responseTime); ProfileExManager.Instance.SetTestDelay(it.IndexId, responseTime);
await UpdateFunc(it.IndexId, responseTime.ToString()); await UpdateFunc(it.IndexId, responseTime.ToString());
@@ -1022,6 +1022,13 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbLegacyProtectTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="9" Grid.Row="9"
@@ -1285,6 +1285,14 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbLegacyProtectTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="9" Grid.Row="9"