1- using System ;
1+ using System ;
2+ using System . Diagnostics ;
23using System . Linq ;
4+ using System . Net . NetworkInformation ;
35using System . Windows . Threading ;
46
57namespace NETworkManager . Models . Network ;
@@ -30,6 +32,12 @@ private void Timer_Tick(object sender, EventArgs e)
3032
3133 #region Variables
3234
35+ /// <summary>
36+ /// The default sample interval in milliseconds. Kept as a constant because the speed
37+ /// calculation and the consuming view model derive timing from it.
38+ /// </summary>
39+ public const double DefaultUpdateInterval = 1000 ;
40+
3341 public double UpdateInterval
3442 {
3543 get ;
@@ -42,12 +50,13 @@ public double UpdateInterval
4250
4351 field = value ;
4452 }
45- } = 1000 ;
53+ } = DefaultUpdateInterval ;
4654
4755 public bool IsRunning => _timer . IsEnabled ;
4856
4957 private readonly DispatcherTimer _timer = new ( ) ;
5058 private readonly System . Net . NetworkInformation . NetworkInterface _networkInterface ;
59+ private readonly Stopwatch _stopwatch = new ( ) ;
5160 private long _previousBytesSent ;
5261 private long _previousBytesReceived ;
5362 private bool _canUpdate ; // Collect initial data for correct calculation
@@ -76,34 +85,60 @@ public void Stop()
7685 {
7786 _timer . Stop ( ) ;
7887
79- // Reset
88+ // Reset, so the next sample re-seeds the baseline (avoids a speed spike after a pause).
8089 _canUpdate = false ;
8190 }
8291
8392 private void Update ( )
8493 {
85- var stats = _networkInterface . GetIPv4Statistics ( ) ;
94+ // The interface may have been removed/disabled after this meter was created.
95+ if ( _networkInterface == null )
96+ return ;
8697
87- var totalBytesSent = stats . BytesSent ;
88- var totalBytesReceived = stats . BytesReceived ;
98+ IPInterfaceStatistics stats ;
8999
90- var byteSentSpeed = totalBytesSent - _previousBytesSent ;
91- var byteReceivedSpeed = totalBytesReceived - _previousBytesReceived ;
100+ try
101+ {
102+ // IPStatistics covers both IPv4 and IPv6 traffic on the interface.
103+ stats = _networkInterface . GetIPStatistics ( ) ;
104+ }
105+ catch ( NetworkInformationException )
106+ {
107+ // Transient failure (e.g. adapter going down) - skip this tick.
108+ return ;
109+ }
92110
93- _previousBytesSent = stats . BytesSent ;
94- _previousBytesReceived = stats . BytesReceived ;
111+ var totalBytesSent = stats . BytesSent ;
112+ var totalBytesReceived = stats . BytesReceived ;
95113
96- // Need to collect initial data for correct calculation.. .
114+ // First sample after start/resume: seed the baseline and start timing, no speed yet .
97115 if ( ! _canUpdate )
98116 {
117+ _previousBytesSent = totalBytesSent ;
118+ _previousBytesReceived = totalBytesReceived ;
119+ _stopwatch . Restart ( ) ;
99120 _canUpdate = true ;
100121
101122 return ;
102123 }
103124
104- OnUpdateSpeed ( new BandwidthMeterSpeedArgs ( DateTime . Now , totalBytesReceived , totalBytesSent , byteReceivedSpeed ,
105- byteSentSpeed ) ) ;
125+ var elapsedSeconds = _stopwatch . Elapsed . TotalSeconds ;
126+ _stopwatch . Restart ( ) ;
127+
128+ // Clamp negative deltas: cumulative counters can reset/wrap (driver reset, disable/enable).
129+ var deltaSent = Math . Max ( 0 , totalBytesSent - _previousBytesSent ) ;
130+ var deltaReceived = Math . Max ( 0 , totalBytesReceived - _previousBytesReceived ) ;
131+
132+ // Derive a true per-second rate from the measured elapsed time (robust against timer jitter).
133+ var byteSentSpeed = elapsedSeconds > 0 ? ( long ) ( deltaSent / elapsedSeconds ) : 0 ;
134+ var byteReceivedSpeed = elapsedSeconds > 0 ? ( long ) ( deltaReceived / elapsedSeconds ) : 0 ;
135+
136+ _previousBytesSent = totalBytesSent ;
137+ _previousBytesReceived = totalBytesReceived ;
138+
139+ OnUpdateSpeed ( new BandwidthMeterSpeedArgs ( DateTime . Now , totalBytesReceived , totalBytesSent ,
140+ byteReceivedSpeed , byteSentSpeed ) ) ;
106141 }
107142
108143 #endregion
109- }
144+ }
0 commit comments