diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index af039b18..86c54214 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -107,67 +107,30 @@ namespace Shadowsocks.Controller var bytes = inbound - lastInbound; _lastInboundCounter[id] = inbound; var inboundSpeed = GetSpeedInKiBPerSecond(bytes, _monitorInterval.TotalSeconds); - _inboundSpeedRecords.GetOrAdd(id, new List {inboundSpeed}).Add(inboundSpeed); + _inboundSpeedRecords.GetOrAdd(id, (k) => + { + List records = new List(); + records.Add(inboundSpeed); + return records; + }); var lastOutbound = _lastOutboundCounter[id]; var outbound = _outboundCounter[id]; bytes = outbound - lastOutbound; _lastOutboundCounter[id] = outbound; var outboundSpeed = GetSpeedInKiBPerSecond(bytes, _monitorInterval.TotalSeconds); - _outboundSpeedRecords.GetOrAdd(id, new List {outboundSpeed}).Add(outboundSpeed); + _outboundSpeedRecords.GetOrAdd(id, (k) => + { + List records = new List(); + records.Add(outboundSpeed); + return records; + }); Logging.Debug( $"{id}: current/max inbound {inboundSpeed}/{_inboundSpeedRecords[id].Max()} KiB/s, current/max outbound {outboundSpeed}/{_outboundSpeedRecords[id].Max()} KiB/s"); } } - private async Task ICMPTest(Server server) - { - Logging.Debug("Ping " + server.FriendlyName()); - if (server.server == "") return null; - var result = new ICMPResult(server); - try - { - var IP = - Dns.GetHostAddresses(server.server) - .First( - ip => - ip.AddressFamily == AddressFamily.InterNetwork || - ip.AddressFamily == AddressFamily.InterNetworkV6); - var ping = new Ping(); - - foreach (var _ in Enumerable.Range(0, Repeat)) - { - try - { - var reply = await ping.SendTaskAsync(IP, TimeoutMilliseconds); - if (reply.Status.Equals(IPStatus.Success)) - { - result.RoundtripTime.Add((int?) reply.RoundtripTime); - } - else - { - result.RoundtripTime.Add(null); - } - - //Do ICMPTest in a random frequency - Thread.Sleep(TimeoutMilliseconds + new Random().Next()%TimeoutMilliseconds); - } - catch (Exception e) - { - Logging.Error($"An exception occured while eveluating {server.FriendlyName()}"); - Logging.LogUsefulException(e); - } - } - } - catch (Exception e) - { - Logging.Error($"An exception occured while eveluating {server.FriendlyName()}"); - Logging.LogUsefulException(e); - } - return result; - } - private void Reset() { _inboundSpeedRecords.Clear(); @@ -183,7 +146,7 @@ namespace Shadowsocks.Controller FilterRawStatistics(); } - private async void UpdateRecords() + private void UpdateRecords() { var records = new Dictionary(); @@ -202,14 +165,11 @@ namespace Shadowsocks.Controller records[id] = record; else records.Add(id, record); - } - - if (Config.Ping) - { - var icmpResults = await TaskEx.WhenAll(_controller.GetCurrentConfiguration().configs.Select(ICMPTest)); - foreach (var result in icmpResults.Where(result => result != null)) + if (Config.Ping) { - records[result.Server.Identifier()].SetResponse(result.RoundtripTime); + MyPing ping = new MyPing(server, Repeat, record); + ping.Completed += ping_Completed; + ping.Start(); } } @@ -219,15 +179,22 @@ namespace Shadowsocks.Controller } } + private void ping_Completed(object sender, MyPing.CompletedEventArgs e) + { + Server server = ((MyPing)sender).server; + StatisticsRecord record = (StatisticsRecord)((MyPing)sender).userstate; + record.SetResponse(e.RoundtripTime); + } + private void AppendRecord(string serverIdentifier, StatisticsRecord record) { List records; if (!RawStatistics.TryGetValue(serverIdentifier, out records)) { records = new List(); + RawStatistics[serverIdentifier] = records; } records.Add(record); - RawStatistics[serverIdentifier] = records; } private void Save() @@ -298,21 +265,10 @@ namespace Shadowsocks.Controller private static int GetSpeedInKiBPerSecond(long bytes, double seconds) { - var result = (int) (bytes/seconds)/1024; + var result = (int)(bytes / seconds) / 1024; return result; } - private class ICMPResult - { - internal readonly List RoundtripTime = new List(); - internal readonly Server Server; - - internal ICMPResult(Server server) - { - Server = server; - } - } - public void Dispose() { _recorder.Dispose(); @@ -321,44 +277,131 @@ namespace Shadowsocks.Controller public void UpdateLatency(Server server, int latency) { - List records; - _latencyRecords.TryGetValue(server.Identifier(), out records); - if (records == null) + _latencyRecords.GetOrAdd(server.Identifier(), (k) => { - records = new List(); - } - records.Add(latency); - _latencyRecords[server.Identifier()] = records; + List records = new List(); + records.Add(latency); + return records; + }); } public void UpdateInboundCounter(Server server, long n) { - long count; - if (_inboundCounter.TryGetValue(server.Identifier(), out count)) - { - count += n; - } - else + _inboundCounter.AddOrUpdate(server.Identifier(), (k) => { - count = n; - _lastInboundCounter[server.Identifier()] = 0; - } - _inboundCounter[server.Identifier()] = count; + _lastInboundCounter.GetOrAdd(server.Identifier(), 0); + return n; + }, (k, v) => (v + n)); } public void UpdateOutboundCounter(Server server, long n) { - long count; - if (_outboundCounter.TryGetValue(server.Identifier(), out count)) + _outboundCounter.AddOrUpdate(server.Identifier(), (k) => + { + _lastOutboundCounter.GetOrAdd(server.Identifier(), 0); + return n; + }, (k, v) => (v + n)); + } + + class MyPing + { + //arguments for ICMP tests + public const int TimeoutMilliseconds = 500; + + public EventHandler Completed; + public Server server; + public object userstate; + + private int repeat; + private IPAddress ip; + private Ping ping; + private List RoundtripTime; + + public MyPing(Server server, int repeat, object userstate) + { + this.server = server; + this.repeat = repeat; + this.userstate = userstate; + RoundtripTime = new List(repeat); + ping = new Ping(); + ping.PingCompleted += Ping_PingCompleted; + } + + public void Start() + { + Logging.Debug("Ping " + server.FriendlyName()); + if (server.server == "") + return; + new Task(() => ICMPTest(0)).Start(); + } + + private void ICMPTest(int delay) + { + try + { + if (ip == null) + { + ip = Dns.GetHostAddresses(server.server) + .First( + ip => + ip.AddressFamily == AddressFamily.InterNetwork || + ip.AddressFamily == AddressFamily.InterNetworkV6); + } + repeat--; + if (delay > 0) + Thread.Sleep(delay); + ping.SendAsync(ip, TimeoutMilliseconds, null); + } + catch (Exception e) + { + Logging.Error($"An exception occured while eveluating {server.FriendlyName()}"); + Logging.LogUsefulException(e); + } + } + + private void Ping_PingCompleted(object sender, PingCompletedEventArgs e) { - count += n; + try + { + if (e.Reply.Status == IPStatus.Success) + { + RoundtripTime.Add((int?)e.Reply.RoundtripTime); + } + else + { + RoundtripTime.Add(null); + } + TestNext(); + } + catch (Exception ex) + { + Logging.Error($"An exception occured while eveluating {server.FriendlyName()}"); + Logging.LogUsefulException(ex); + } } - else + + private void TestNext() { - count = n; - _lastOutboundCounter[server.Identifier()] = 0; + if (repeat > 0) + { + //Do ICMPTest in a random frequency + int delay = TimeoutMilliseconds + new Random().Next() % TimeoutMilliseconds; + new Task(() => ICMPTest(delay)).Start(); + } + else + { + Completed?.Invoke(this, new CompletedEventArgs + { + RoundtripTime = RoundtripTime + }); + } + } + + public class CompletedEventArgs : EventArgs + { + public List RoundtripTime; } - _outboundCounter[server.Identifier()] = count; } + } } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 13c6650d..8a66ee63 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -5,7 +5,6 @@ using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; -using System.Threading.Tasks; using Newtonsoft.Json; using Shadowsocks.Controller.Strategy; @@ -311,7 +310,7 @@ namespace Shadowsocks.Controller { if (_config.availabilityStatistics) { - new Task(() => availabilityStatistics.UpdateLatency(server, (int) latency.TotalMilliseconds)).Start(); + availabilityStatistics.UpdateLatency(server, (int)latency.TotalMilliseconds); } } @@ -320,7 +319,7 @@ namespace Shadowsocks.Controller Interlocked.Add(ref inboundCounter, n); if (_config.availabilityStatistics) { - new Task(() => availabilityStatistics.UpdateInboundCounter(server, n)).Start(); + availabilityStatistics.UpdateInboundCounter(server, n); } } @@ -329,7 +328,7 @@ namespace Shadowsocks.Controller Interlocked.Add(ref outboundCounter, n); if (_config.availabilityStatistics) { - new Task(() => availabilityStatistics.UpdateOutboundCounter(server, n)).Start(); + availabilityStatistics.UpdateOutboundCounter(server, n); } } diff --git a/shadowsocks-csharp/packages.config b/shadowsocks-csharp/packages.config index 6f3efda8..b80520d3 100644 --- a/shadowsocks-csharp/packages.config +++ b/shadowsocks-csharp/packages.config @@ -3,11 +3,6 @@ - - - - - \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 008134ae..93fdfc73 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -66,18 +66,6 @@ - - 3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - True - - - 3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - True - - - 3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - True - 3rd\Newtonsoft.Json.8.0.2\lib\net40\Newtonsoft.Json.dll @@ -88,27 +76,7 @@ - - 3rd\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll - True - - - 3rd\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll - True - - - 3rd\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll - True - - - 3rd\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll - True - - - 3rd\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll - True - @@ -330,10 +298,8 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - diff --git a/test/packages.config b/test/packages.config deleted file mode 100644 index 7d90c6e3..00000000 --- a/test/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/test/test.csproj b/test/test.csproj index 777a10b8..d1c3fa2e 100755 --- a/test/test.csproj +++ b/test/test.csproj @@ -35,29 +35,9 @@ - - ..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - True - - - ..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - True - - - ..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - True - - - ..\shadowsocks-csharp\3rd\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll - True - - - ..\shadowsocks-csharp\3rd\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll - True - @@ -82,9 +62,6 @@ shadowsocks-csharp - - - @@ -105,13 +82,6 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - -