mirror of
https://github.com/netchx/netch.git
synced 2026-03-14 17:43:18 +08:00
Feature: Server http connect time Test
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Netch.Enums;
|
||||
@@ -168,10 +169,16 @@ namespace Netch.Controllers
|
||||
PortCheck(port, portName, PortType.TCP);
|
||||
}
|
||||
|
||||
public static async Task<NatTypeTestResult> NatTestAsync()
|
||||
public static async Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
return await NatTypeTester.StartAsync(Socks5Server);
|
||||
return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
|
||||
}
|
||||
|
||||
public static async Task<int?> HttpConnectAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Netch/Forms/MainForm.Designer.cs
generated
20
Netch/Forms/MainForm.Designer.cs
generated
@@ -73,6 +73,7 @@
|
||||
this.DownloadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.UploadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.blankToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.TcpStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.NatTypeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.NatTypeStatusLightLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
@@ -521,6 +522,7 @@
|
||||
this.DownloadSpeedLabel,
|
||||
this.UploadSpeedLabel,
|
||||
this.blankToolStripStatusLabel,
|
||||
this.TcpStatusLabel,
|
||||
this.NatTypeStatusLabel,
|
||||
this.NatTypeStatusLightLabel});
|
||||
this.StatusStrip.Location = new System.Drawing.Point(0, 272);
|
||||
@@ -560,9 +562,18 @@
|
||||
// blankToolStripStatusLabel
|
||||
//
|
||||
this.blankToolStripStatusLabel.Name = "blankToolStripStatusLabel";
|
||||
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(494, 17);
|
||||
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(240, 17);
|
||||
this.blankToolStripStatusLabel.Spring = true;
|
||||
//
|
||||
// TcpStatusLabel
|
||||
//
|
||||
this.TcpStatusLabel.Name = "TcpStatusLabel";
|
||||
this.TcpStatusLabel.Size = new System.Drawing.Size(33, 17);
|
||||
this.TcpStatusLabel.Text = "TCP:";
|
||||
this.TcpStatusLabel.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
|
||||
this.TcpStatusLabel.Visible = false;
|
||||
this.TcpStatusLabel.Click += new System.EventHandler(this.TcpStatusLabel_Click);
|
||||
//
|
||||
// NatTypeStatusLabel
|
||||
//
|
||||
this.NatTypeStatusLabel.Name = "NatTypeStatusLabel";
|
||||
@@ -609,19 +620,19 @@
|
||||
this.ExitToolStripButton});
|
||||
this.NotifyMenu.Name = "NotifyMenu";
|
||||
this.NotifyMenu.ShowItemToolTips = false;
|
||||
this.NotifyMenu.Size = new System.Drawing.Size(181, 70);
|
||||
this.NotifyMenu.Size = new System.Drawing.Size(108, 48);
|
||||
//
|
||||
// ShowMainFormToolStripButton
|
||||
//
|
||||
this.ShowMainFormToolStripButton.Name = "ShowMainFormToolStripButton";
|
||||
this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(180, 22);
|
||||
this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(107, 22);
|
||||
this.ShowMainFormToolStripButton.Text = "Show";
|
||||
this.ShowMainFormToolStripButton.Click += new System.EventHandler(this.ShowMainFormToolStripButton_Click);
|
||||
//
|
||||
// ExitToolStripButton
|
||||
//
|
||||
this.ExitToolStripButton.Name = "ExitToolStripButton";
|
||||
this.ExitToolStripButton.Size = new System.Drawing.Size(180, 22);
|
||||
this.ExitToolStripButton.Size = new System.Drawing.Size(107, 22);
|
||||
this.ExitToolStripButton.Text = "Exit";
|
||||
this.ExitToolStripButton.Click += new System.EventHandler(this.ExitToolStripButton_Click);
|
||||
//
|
||||
@@ -792,5 +803,6 @@
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
|
||||
private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel TcpStatusLabel;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Windows.Win32;
|
||||
@@ -90,8 +91,8 @@ namespace Netch.Forms
|
||||
// 加载翻译
|
||||
TranslateControls();
|
||||
|
||||
// 隐藏 NatTypeStatusLabel
|
||||
NatTypeStatusText();
|
||||
// 隐藏 ConnectivityStatusLabel
|
||||
ConnectivityStatusVisible(false);
|
||||
|
||||
// 加载快速配置
|
||||
LoadProfiles();
|
||||
@@ -547,7 +548,8 @@ namespace Netch.Forms
|
||||
State = State.Started;
|
||||
|
||||
Task.Run(Bandwidth.NetTraffic).Forget();
|
||||
NatTestAsync().Forget();
|
||||
DiscoveryNatTypeAsync().Forget();
|
||||
HttpConnectAsync().Forget();
|
||||
|
||||
if (Global.Settings.MinimizeWhenStarted)
|
||||
Minimize();
|
||||
@@ -1028,7 +1030,7 @@ namespace Netch.Forms
|
||||
|
||||
ProfileGroupBox.Enabled = false;
|
||||
BandwidthState(false);
|
||||
NatTypeStatusText();
|
||||
ConnectivityStatusVisible(false);
|
||||
break;
|
||||
case State.Stopped:
|
||||
ControlButton.Enabled = true;
|
||||
@@ -1099,18 +1101,14 @@ namespace Netch.Forms
|
||||
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = state;
|
||||
}
|
||||
|
||||
private void NatTypeStatusText(string? text = null, string? country = null)
|
||||
private void UpdateNatTypeStatusLabelText(string? text, string? country = null)
|
||||
{
|
||||
if (State != State.Started)
|
||||
{
|
||||
NatTypeStatusLabel.Text = "";
|
||||
NatTypeStatusLabel.Visible = NatTypeStatusLightLabel.Visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} {(!country.IsNullOrEmpty() ? $"[{country}]" : "")}";
|
||||
if (country == null)
|
||||
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} ";
|
||||
else
|
||||
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} [{country}]";
|
||||
|
||||
UpdateNatTypeLight(int.TryParse(text, out var natType) ? natType : -1);
|
||||
}
|
||||
@@ -1122,10 +1120,18 @@ namespace Netch.Forms
|
||||
NatTypeStatusLabel.Visible = true;
|
||||
}
|
||||
|
||||
private void ConnectivityStatusVisible(bool visible)
|
||||
{
|
||||
if (!visible)
|
||||
TcpStatusLabel.Text = NatTypeStatusLabel.Text = "";
|
||||
|
||||
TcpStatusLabel.Visible = NatTypeStatusLabel.Visible = NatTypeStatusLightLabel.Visible = visible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新 NAT指示灯颜色
|
||||
/// </summary>
|
||||
/// <param name="natType"></param>
|
||||
/// <param name="natType">NAT Type. keep default(-1) to Hide Light</param>
|
||||
private void UpdateNatTypeLight(int natType = -1)
|
||||
{
|
||||
if (natType > 0 && natType < 5)
|
||||
@@ -1148,43 +1154,76 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private async void NatTypeStatusLabel_Click(object sender, EventArgs e)
|
||||
private async void TcpStatusLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
await NatTestAsync();
|
||||
await HttpConnectAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 NAT
|
||||
/// </summary>
|
||||
private async Task NatTestAsync()
|
||||
private async void NatTypeStatusLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
await DiscoveryNatTypeAsync();
|
||||
}
|
||||
|
||||
private async Task DiscoveryNatTypeAsync()
|
||||
{
|
||||
NatTypeStatusLabel.Enabled = false;
|
||||
NatTypeStatusLabel.Text = i18N.Translate("Testing NAT Type");
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
|
||||
var discoveryNatTypeAsync = MainController.DiscoveryNatTypeAsync(cts.Token);
|
||||
|
||||
try
|
||||
{
|
||||
NatTypeStatusText(i18N.Translate("Testing NAT Type"));
|
||||
|
||||
var res = await MainController.NatTestAsync();
|
||||
var res = await discoveryNatTypeAsync;
|
||||
|
||||
if (!string.IsNullOrEmpty(res.PublicEnd))
|
||||
{
|
||||
var country = await Utils.Utils.GetCityCodeAsync(res.PublicEnd);
|
||||
NatTypeStatusText(res.Result, country);
|
||||
|
||||
UpdateNatTypeStatusLabelText(res.Result, country);
|
||||
if (int.TryParse(res.Result, out var natType))
|
||||
UpdateNatTypeLight(natType);
|
||||
else
|
||||
UpdateNatTypeLight();
|
||||
}
|
||||
else
|
||||
{
|
||||
NatTypeStatusText(res.Result ?? "Error");
|
||||
UpdateNatTypeStatusLabelText(res.Result ?? "Error");
|
||||
NatTypeStatusLightLabel.Visible = false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NatTypeStatusText(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NatTypeStatusLabel.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HttpConnectAsync()
|
||||
{
|
||||
TcpStatusLabel.Enabled = false;
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
var httpConnectAsync = MainController.HttpConnectAsync(cts.Token);
|
||||
|
||||
try
|
||||
{
|
||||
var httpRes = await httpConnectAsync;
|
||||
if (httpRes != null)
|
||||
TcpStatusLabel.Text = $"TCP{i18N.Translate(": ")}{httpRes}ms";
|
||||
else
|
||||
TcpStatusLabel.Text = $"TCP{i18N.Translate(": ", "Timeout")}";
|
||||
|
||||
TcpStatusLabel.Visible = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
TcpStatusLabel.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
@@ -11,9 +13,9 @@ using STUN.StunResult;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class NatTypeTester
|
||||
public static class Socks5ServerTestUtils
|
||||
{
|
||||
public static async Task<NatTypeTestResult> StartAsync(Socks5Server socks5, CancellationToken ctx = default)
|
||||
public static async Task<NatTypeTestResult> DiscoveryNatTypeAsync(Socks5Server socks5, CancellationToken ctx = default)
|
||||
{
|
||||
var stunServer = Global.Settings.STUN_Server;
|
||||
var port = (ushort)Global.Settings.STUN_Server_Port;
|
||||
@@ -30,7 +32,11 @@ namespace Netch.Utils
|
||||
}
|
||||
};
|
||||
|
||||
var ip = await DnsUtils.LookupAsync(stunServer) ?? throw new MessageException("Wrong STUN Server!");
|
||||
var ip = await DnsUtils.LookupAsync(stunServer);
|
||||
if (ip == null)
|
||||
{
|
||||
return new NatTypeTestResult { Result = "Wrong STUN Server!" };
|
||||
}
|
||||
|
||||
using IUdpProxy proxy = ProxyFactory.CreateProxy(ProxyType.Socks5, new IPEndPoint(IPAddress.Loopback, 0), socks5Option);
|
||||
using var client = new StunClient5389UDP(new IPEndPoint(ip, port), local, proxy);
|
||||
@@ -72,5 +78,29 @@ namespace Netch.Utils
|
||||
return res.FilteringBehavior.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<int?> HttpConnectAsync(Socks5Server socks5, CancellationToken ctx)
|
||||
{
|
||||
var socks5Option = new Socks5CreateOption
|
||||
{
|
||||
Address = await DnsUtils.LookupAsync(socks5.Hostname),
|
||||
Port = socks5.Port,
|
||||
UsernamePassword = new UsernamePassword
|
||||
{
|
||||
UserName = socks5.Username,
|
||||
Password = socks5.Password
|
||||
}
|
||||
};
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
var result = await Socks5.Utils.Socks5TestUtils.Socks5ConnectAsync(socks5Option, token: ctx);
|
||||
|
||||
stopwatch.Stop();
|
||||
if (result)
|
||||
return Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user