Quick and dirty network usage meter with C#

Download source code.
Refer to "ReadmeFirst.txt" for instruction on how to run.

I have always been doubtful of my billing by my internet providers. I wanted to write some code that could help me get a rough estimate of bandwidth I was using in every session. In this article, I will show you how to create a very basic network usage meter for serial port/USB/mobile phone modems with only C# (no Win API calls, sockets or fancy stuff).
The network meter's icon (one with yellow dot). Note that network icon status.
The icon's tooltip shows usage. Note that network icon status.

Some entries from the log file.The last entry corresponds to reported usage.
Clicking on 'Exit' menu item will close the program.

I have always been doubtful of my billing by my internet providers. I wanted to write some code that could help me get a rough estimate of bandwidth I was using in every session. In this article, I will show you how to create a very basic network usage meter for serial port/USB/mobile phone modems with only C# (no Win API calls, sockets or fancy stuff). My program is not as sophisticated as others available on the internet, but it does work well for me. It shows usage in current session and logs it in a file. This code should work with many USB modems which actually setup a COM port for communication (example GPRS/3G/HSIA data cards or mobile phones being used as modems).

The basics

The reason, I call this code 'dirty' is, it not well tested and was written in hurry. The program revolves around only two concepts: My program has only been tested with HSIA modem, which gets connected to a virtual COM4 port. The program is written in such a way that it handles frequent connection/disconnection and tries to log usage in every session.

The Code

This is a winforms application. In the constructor of the Form we :
  • Create two performance counters, one for measuring downloads and another for measuring uploads.
  • A Timer to poll the performance counters, so that we can check if they are readable (network/port is available).
  • Attach event handler to 'NetworkAvailabilityChanged' event of 'NetworkChange' class, so that we are updated when the COM4 port is available.
The code is given below:
	 static PerformanceCounter dataSentCounter;
        static PerformanceCounter dataReceivedCounter;
        System.Timers.Timer  networkMonitor;
        string category, instance, fileName;
        static float u, d;

        public Form1()
        {
             InitializeComponent();
             category = ConfigurationSettings.AppSettings["Category"];
             instance = ConfigurationSettings.AppSettings["Instance"];
             fileName = ConfigurationSettings.AppSettings["FilePath"];
             dataSentCounter = new PerformanceCounter(category, "Bytes Transmitted", instance);
             dataReceivedCounter = new PerformanceCounter(category, "Bytes Received", instance);
             NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
             networkMonitor = new System.Timers.Timer();
             networkMonitor.Interval = Int32.Parse(ConfigurationSettings.AppSettings["NetworkPollInterval"]);
             networkMonitor.Elapsed += new ElapsedEventHandler(networkMonitor_Elapsed);         
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                u = dataSentCounter.NextValue();
                d = dataReceivedCounter.NextValue();
            }
            catch
            { return; }
            networkMonitor.Start();
        }
In the above code, 'category' is set to "RAS Port" and 'instance' to "COM4". The instance needs to be set to correct port number to which your modem is connected to. To get instance name of your COM port you can do something like this:
PerformanceCounterCategory c = new PerformanceCounterCategory("RAS Port");
//c.GetInstanceNames() gives list of all instance names.
//Typically there will not be many COM ports. Use guess work
// and some experimenting to get the correct name. Make sure that you
// are connected to internet using a COM port before executing this.
Another important value is "Interval" of the timer. It should be sufficiently high (ideally 1-3 seconds). If you keep it too low the code might now work, because it seems the 'NetworkAvailabilityChanged' event takes some time to fire once you are physcially disconnected from the network. (Another reason for calling this code 'dirty'). Two important pieces are the 'NetworkAvailabilityChanged' event handler and code for 'Elapsed' event of the timer. When the timer's 'Elapsed' event fires, I try to read from the performance counters. If there is an exception reading, or 0 bytes recorded in the read operation, we first log the prior readings to a file. This indicates that the COM4 port was removed or network connectivity was lost. Notice here that, I am NOT relying on 'NetworkAvailabilityChanged' change event to inform me of a connection drop. (Why ..I told you, this is a 'dirty' approach).Instead we only use the 'NetworkAvailabilityChanged' event to check if a new network is available. When network is available we simply start the timer again.

        void networkMonitor_Elapsed(object sender, ElapsedEventArgs e)
        {
            float temp_u=0, temp_d=0;
            try
            {   temp_u  = dataSentCounter.NextValue();
                temp_d = dataReceivedCounter.NextValue();

            }
            catch  
            {
                LogUsage();
                u = 0; d = 0;
                networkMonitor.Stop();
                return;
            }

            if (temp_u == 0f && temp_d == 0f)
            {
                LogUsage();
                networkMonitor.Stop();
                return;
            }
            u = temp_u; d = temp_d;          
        }
  

        void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
        {
            if (e.IsAvailable)
            {networkMonitor.Start();}             
        }

As you can see from the screen shot, I have added a notification icon to the Form. When user moves mouse pointer over this icon, it shows the usage. If the user right clicks, a popup menu comes up with "exit" item. On clicking this, our application closes. The code for this part is given below:
        private void notifyIcon1_MouseMove(object sender, MouseEventArgs e)
        {
            notifyIcon1.Text = string.Format("{0}\nDn:{1} bytes, Ul:{2} bytes",instance,d,u);           
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        { this.Close(); }


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            LogUsage();
            dataSentCounter.Close();
            dataReceivedCounter.Close();                     
        }
The code for function that performs loggin of the usage in a CSV file.
        private void WriteUsageToFile()
        {
             if (!File.Exists(fileName))
                File.Create(fileName);

            string username = System.Environment.UserName;
            string logEntry = string.Format("{0},{1},{2},{3}\n", d, u, username, DateTime.Now.ToLongTimeString());
            File.AppendAllText(fileName, logEntry);
        }

        private void LogUsage()
        {
            try
            {
                if(u > 0f || d > 0f) 
               WriteUsageToFile();
                u = 0; d = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
                networkMonitor.Stop();
            }

        }

Finally!

Hope you found this article useful. Download and try running the code with your serial port/USB modems. Add a shortcut to your "StartUp" folder, so that the program starts automatically everytime the system boots. If the above code does not work 'as is' for you, try customizing it according to your needs. Next week, I will try to see if I can get this code working with wireless network and LAN. I will add my findings to this post. Please leave a comments to share your thoughts. Thank you for reading.


Copyright (c) 2007-2017 Ashish Patil . Please read FAQ for more details.

comments powered by Disqus