Skip to content

Basic implementation of showing network statistics on the Remote Application

I mentioned in #9 (closed) that having some networking stats would be quite handy. Instead of leaving that burden on you, I thought I'd go and do it myself :)

I'm not sure if I'm 100% conforming to your coding style, but I'd greatly appreciate feedback on this. I opted to not make it configurable and rather felt it important to display networking stats by default as it can be very handy for someone trying to understand what the bandwidth requirements of the application will be. I've now also managed to get one step closer to figuring out how to set up a test bench if I ever find the time to try and improve the bandwidth usage.

image

Considerations

I haven't bumped any versions as I felt you'd want more control over what the latest version should be. If you want me to make the relevant changes, please just let me know where so I can go do that.

NetStatistics

The algorithm to calculate averages is relatively straightforward but could be weird to understand if unfamiliar with a ring buffer. The NetStatistics class only exposes total statistics to me so I start a stopwatch and sample values from the instance of NetStatistics as well as the stopwatch. A previously sampled time and bytes value can then be subtracted to discover how much data has been transferred during the last "frame" of time. These samples are then stored in a ring buffer that allows me to have a collection I can write to for aggregation purposes, but once I reach the buffer's capacity I the buffer will overwrite the oldest items contained in it. From there it's as simple as summing together the values and then calculating the bytes per second value. It's not 100% precise, but I try to keep as much precision before truncating by multiplying the total bytes by 1000 before dividing by the total milliseconds.

LiteNetLib

Version 0.7.7.3 of LiteNetLib had its net statistics hiding behind a compile flag and the binaries downloaded from Nuget seem to have been compiled without said compile flag. Bumping to the latest version (0.9.4) fixes this as the library hoists statistics to the level of code configuration.

It did bring with it a few code alterations that I had to make, but from the screenshot below you'll note that everything is still working. The main difference I found was that the concept of "network discovery" had been changed into "network broadcasting", which has also brought with it a few enum changes.

The other big change was the instead of having a type-specific to the library for representing endpoints, the library switched to the IPEndPoint type as can be found in the System.Net namespace. Unfortunately, it's a relatively new type brought to the .NET Framework that hasn't gotten nice parsing methods added as well. These were only added as part of .NET-Core 3 so I had to do some manual parsing and included it as a utility in Remote.Common.

Edit: I found that LiteNetLib has a utility function that can make endpoints using a string IP address and int port number. It also looks like we might get DNS resolution for free which should make configuring for a connection outside your network easier. I have DDNS set up on my personal router so it would make connections from a friend serving as race engineer remotely relatively straightforward.

Overall project feedback

It's taken me a while to get to grips with the overall architecture of the app. I have no qualms with the architecture itself, but understanding how projects relate to one another is a little confusing. I might suggest the following file structure as a slightly different approach:

  • Applications
    • SecondMonitor
    • ManagePlugins
    • TelemetryLauncher
  • Connectors
    • AccConnector
    • AMS2Connector
    • AssettoCorsaConnector
    • F12019
    • MockedConnector
    • PCars2Connector
    • PCarsConnector
    • R3EConnector
    • Remote.Connector
    • RF2Connector
    • RFactorConnector
  • Plugins
    • Remote.Application
    • Timing.Application

The rest can be structured as they are currently, but this will hopefully help make it quite clear what is meant for what. It's very likely because my WPF experience is extremely limited, but it took me a while to realise these items were being loaded dynamically so it wasn't immediately obvious when glancing at a generated project diagram in Rider that there are dependencies running in certain directions. Anyhoos, I do hope that this small feature can make its way into the main app. Hoping to provide some future contributions as well!

Edited by Sas van der Westhuizen

Merge request reports