use strict; use warnings; # perl snmp_server.pl | wc -l use threads; use Thread::Queue; use Time::HiRes qw( sleep time ); use Storable qw( freeze thaw ); use Net::SNMPTrapd; use MCE::Shared; my $queue = Thread::Queue->new(); my $max_consumers = 30; my $start = 0; mce_open my $outfh, '>>', \*STDOUT; mce_open my $errfh, '>>', \*STDERR; threads->create(\&consumer) for 1 .. $max_consumers; listener(); $_->join for threads->list(); printf {$errfh} "duration : %0.03f seconds\n", time - $start; exit(0); sub listener { my $snmptrapd = Net::SNMPTrapd->new( ReusePort => 1 ); my $count = 0; while ( 1 ) { my $trap = $snmptrapd->get_trap(); if ( !defined $trap ) { printf {$errfh} "$0: %s\n", Net::SNMPTrapd->error(); next; } elsif ( $trap == 0 ) { next; } $start = time() unless $start; # important, remove the file handle inside the object delete $trap->{_UDPSERVER_}; # enqueue the trap for a consumer to process $queue->enqueue( freeze($trap) ); # leave the loop after 10,000 traps last if ( ++$count >= 10000 ); # reset the counter to not overflow $count = 0 if ( $count > 2e9 ); } # $queue->end(); # newer Thread::Queue and MCE::Shared releases $queue->enqueue((undef) x $max_consumers); # older releases printf {$errfh} "enqueue : %0.03f seconds\n", time - $start; printf {$errfh} "pending : %d\n", $queue->pending(); } sub consumer { while ( defined ( my $item = $queue->dequeue() ) ) { my $trap = thaw($item); $trap->process_trap(); printf {$outfh} "[$$] %s\t%i\t%i\t%s\n", $trap->remoteaddr, $trap->remoteport, $trap->version, $trap->community; sleep 0.004; } }