How to monitor network interface traffic in Perl?

Question

How to monitor network interface traffic in Perl?

Monitoring network interface traffic in Perl typically involves reading Linux’s /proc/net/dev file, which contains cumulative counters of bytes and packets for each interface. However, in sandboxed or restricted environments where /proc/net/dev is unavailable, this direct approach cannot run successfully.

To provide a runnable example that works in any environment (including sandboxes), we can simulate network data by hardcoding sample input from /proc/net/dev and parsing that instead. This approach retains the core logic of parsing and calculating traffic rates, illustrating the Perl concepts involved, while avoiding external dependencies or filesystem access.

Key Perl Concepts Illustrated

  • open replaced by reading from a string (simulated filehandle via Perl’s open on scalar ref)
  • Regex parsing and split for extracting fields
  • Hashrefs to store and compare interface counters at two points in time
  • Simple rate calculation over a specified interval
  • Demonstration of Perl’s sigils ($ scalar, @ array, % hashes)
  • Explicit sorting of interfaces for consistent output

Common Pitfall Avoidance

  • Directly reading non-existent files causes errors in restricted environments
  • Parsing error-prone system commands avoided here in favor of stable input format
  • Ensure timing intervals > 0 to avoid divide-by-zero

Simulated Network Traffic Monitoring in Perl

#!/usr/bin/perl
use strict;
use warnings;

# Simulated contents of /proc/net/dev at two points in time (1 second apart)
my $proc_net_dev_1 = <<'END';
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0: 1000000  10000   0    0    0    0     0          0          2000000  20000   0    0    0    0     0       0
   lo:  500000   5000   0    0    0    0     0          0           500000   5000   0    0    0    0     0       0
END

my $proc_net_dev_2 = <<'END';
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0: 1500000  15000   0    0    0    0     0          0          2300000  23000   0    0    0    0     0       0
   lo:  510000   5100   0    0    0    0     0          0           510000   5100   0    0    0    0     0       0
END

# Parse proc/net/dev-style data from a string and return hashref of stats
sub parse_net_dev {
    my ($input) = @_;
    my %stats;

    open my $fh, '<', \$input or die "Failed to open string as filehandle: $!";
    while (<$fh>) {
        next if /^Inter|face|^\s*$/;  # Skip headers and blank lines
        if (/^\s*(\S+):\s*(.+)/) {
            my ($iface, $data) = ($1, $2);
            my @fields = split /\s+/, $data;
            $stats{$iface} = {
                rx_bytes   => $fields[0],
                rx_packets => $fields[1],
                tx_bytes   => $fields[8],
                tx_packets => $fields[9],
            };
        }
    }
    close $fh;
    return \%stats;
}

# Calculate and print traffic rate given two stat snapshots and interval
sub print_traffic_rates {
    my ($old, $new, $interval) = @_;
    die "Interval must be positive" unless $interval > 0;

    print "Interface Traffic Rates (bytes/sec) over ${interval}s interval:\n";
    for my $iface (sort keys %$new) {
        next unless exists $old->{$iface};
        my $rx_rate = ($new->{$iface}{rx_bytes} - $old->{$iface}{rx_bytes}) / $interval;
        my $tx_rate = ($new->{$iface}{tx_bytes} - $old->{$iface}{tx_bytes}) / $interval;
        printf "%-6s RX: %10.0f B/s   TX: %10.0f B/s\n", $iface, $rx_rate, $tx_rate;
    }
}

# Main logic
my $interval = 1;  # seconds

my $stats1 = parse_net_dev($proc_net_dev_1);
my $stats2 = parse_net_dev($proc_net_dev_2);

print_traffic_rates($stats1, $stats2, $interval);

Explanation

This script simulates reading network interface stats at two time points by parsing string data formatted like /proc/net/dev. The parse_net_dev function uses a filehandle opened on a scalar reference—which is a neat Perl feature—to mimic reading from a file without touching the real filesystem.

It then calculates the difference in bytes received and transmitted, dividing by the interval to get bytes per second. The output clearly shows traffic rates for each interface (simulated eth0 and lo).

This approach demonstrates Perl’s flexibility (TMTOWTDI) by replacing unavailable system files with internal data sources, allowing the core logic of network monitoring to be developed and tested anywhere.

Extending Real Usage

  • Replace the hardcoded strings with live reads from /proc/net/dev on real Linux systems.
  • Improve parsing for unusual interface names or additional statistics.
  • Add continuous looping with timestamps and formatting (KB/s, MB/s).
  • Consider cross-platform tools or modules for non-Linux environments.

This solution balances sandbox constraints with practical demonstration of Perl network monitoring skills.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 13ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Interface Traffic Rates (bytes/sec) over 1s interval:
eth0   RX:     500000 B/s   TX:     300000 B/s
lo     RX:      10000 B/s   TX:      10000 B/s
STDERR
(empty)

Was this helpful?

Related Questions