netmeter.pl
#!/usr/bin/perl -w
# ---------------------------------------------------------
# netmeter.pl (v 0.2): shows the network's load;
# based on Loris Degioanni's NetMeter program in C
# (see the Packet Capture Driver Developer's Pack).
# This simple example shows how to use statistics
# mode with Win32::NetPacket.
# This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.
# (c) 2003-2006 J-L Morel jlmorel@cpan.org
# ---------------------------------------------------------
use strict;
use Tk;
use Win32::NetPacket qw/ GetAdapterNames :ndis :mode /;
my $mw = MainWindow->new;
my $go = 1;
$mw->protocol( 'WM_DELETE_WINDOW' => sub { $go = 0 } );
my $w = 300;
my $h = 110;
my $t = 2;
my $nbb = $w / $t + 1;
my $can = $mw->Canvas(
-width => $w,
-height => $h + 10,
-background => 'black',
)->pack();
$can->configure( -scrollregion => [ 0, 0, $w, $h + 20 ] );
$can->createGrid( 0, 10, $w, 30, -line => 1, -fill => 'green' );
# open adapter
my $nic = Win32::NetPacket->new(
driver_buff_size => 0, # no buffer needed
read_timeout => 1000, # every second
mode => MODE_STAT, # statistics mode
) or die $@;
$nic->SetHwFilter(NDIS_PACKET_TYPE_PROMISCUOUS); # set nic in promiscuous mode
my $Buff;
$nic->SetUserBuffer( $Buff, 36 ); # 36 bytes user's buffer, it's enough
# initialisation
my ( $old_tv_sec, $old_tv_usec ) = ( 0, 0 );
my @group = ();
my $count = 0;
my $BpsMax = 1_000_000; # max grad = 1 Mbps
# 2 padding bytes (xx) in the bpf_hdr structure under WinNT
my $patern = Win32::IsWinNT() ? "llIISxxLLLL" : "llIISLLLL";
# my MainLoop !
while ($go) {
$nic->ReceivePacket(); # get stat
my ( $tv_sec, $tv_usec, $caplen, $datalen, $hdrlen, $p0, $p1, $b0, $b1 )
= unpack $patern, $Buff; # read the buffer
# Calculate the delay in seconds from the last sample.
my $delay = ( $tv_sec - $old_tv_sec ) + ( $tv_usec - $old_tv_usec ) * 1e-6;
$old_tv_sec = $tv_sec;
$old_tv_usec = $tv_usec;
# get the number of bits per second
my $Bps = int( ( $b1 * 2**32 + $b0 ) * 8 / $delay );
my $band = $Bps * 100 / $BpsMax;
push @group,
$can->createRectangle( $w, $h, $w - $t, $h - $band, -outline => 'yellow',
);
$can->delete( shift @group ) if @group >= $nbb;
$can->move( $_, -$t, 0 ) foreach (@group);
$count++;
$mw->update();
}