Everything works fine, except that when the client exits, its session doesn't terminate. I suspect this is because of the way I am handling the timer. I start the timer in 'child_start' event and the timer calls the 'flush_register' event. Inside the 'flush_register' event, I do what I need and then restart the timer again. This way, the timer is on a continuous 3-second interval.
Below is the Perl program, followed by the output from a sample run. When looking at the sample output, be aware that the client exits at 15:31:15, the timer continues beyond this time, and I CTRL-C the server at 15:31:21. I'm basically stuck in a loop I presume because a reference to the session still exists?
What I would really like is for the timer to no longer work once the child exits. However, 'child_stop' doesn't appear to execute until I CTRL-C the server, not when the child exits. I tried $poe_kernel->alarm_remove_all() in 'child_stop' but of course that didn't change anything.
Any advice to help steer me in the correct general direction would be greatly appreciated.
With my thanks, David
#!/usr/bin/perl -w
use strict;
use Socket qw(inet_ntoa);
use Time::HiRes;
use POE qw(Wheel::SocketFactory Wheel::ReadWrite
Filter::Line Driver::SysRW);use constant PORT => 31008;
POE::Session->create ( inline_states => { _start => \&server_start, _stop => \&server_stop, accept_new_client => \&accept_new_client, accept_failed => \&accept_failed, child_input => \&child_input, child_error => \&child_error } );
$poe_kernel->run();
############### # SUBROUTINES # ####################################################################### sub server_start { $_[HEAP]->{listener} = new POE::Wheel::SocketFactory ( BindPort => PORT, Reuse => 'on', SuccessEvent => 'accept_new_client', FailureEvent => 'accept_failed' );
print "SERVER: Started listening on port ", PORT, ".\n"; }
sub flush_register {
my $heap = $_[HEAP];
my $session_id = $_[SESSION]->ID; my $register = $heap->{register};
push @{ $heap->{conveyor} }, $register;
$heap->{register} -= $register; print scalar(localtime()), " Removed $register from register ",
"$session_id.\n"; # Renew the timer that moves from register to conveyor every 3 sec
$_[KERNEL]->delay_set(flush_register => 3);
}sub accept_new_client {
my ($socket, $peeraddr, $peerport) = @_[ARG0 .. ARG2];
$peeraddr = inet_ntoa($peeraddr); POE::Session->create (
inline_states => {
_start => \&child_start,
_stop => \&child_stop,
flush_register => \&flush_register
},
package_states => [
main => [ 'child_input', 'child_done', 'child_error' ]
],
args => [ $socket, $peeraddr, $peerport ]
);print "SERVER: Got connection from $peeraddr:$peerport.\n"; }
sub child_input {
my $data = $_[ARG0];
my $heap = $_[HEAP]; unless ($data =~ /^\d{1,10}$/) {
print "SERVER: Got bad data from child: [$data]\n";
return;
}my $session_id = $_[SESSION]->ID;
$heap->{actual} += $data;
$heap->{register} += $data; print scalar(localtime()),
" CHILD: Got input from peer $session_id: ",
"\"$data\" ($heap->{register}).\n";
}sub child_start {
my ($heap, $socket) = @_[HEAP, ARG0]; $heap->{readwrite} = new POE::Wheel::ReadWrite (
Handle => $socket,
Driver => new POE::Driver::SysRW (),
Filter => new POE::Filter::Line (),
InputEvent => 'child_input',
ErrorEvent => 'child_error'
); $heap->{readwrite}->put('Hello, client!');
$heap->{peername} = join ':', @_[ARG1, ARG2];
print "CHILD: Connected to $heap->{peername}.\n"; $heap->{actual} = 0;
$heap->{register} = 0;$heap->{conveyor} = [];
# Start a timer that moves from register to conveyor every 3 seconds
$_[KERNEL]->delay_set(flush_register => 3);
}sub child_stop {
my $heap = $_[HEAP];
print "CHILD: Stopped.\n";
print "Totals: Actual: $heap->{actual}, Register: $heap->{register}.\n";
}
sub child_done {
delete $_[HEAP]->{readwrite};
print "CHILD: Disconnected from ", $_[HEAP]->{peername}, ".\n";
}sub child_error {
my ($function, $error) = @_[ARG0, ARG2];
delete $_[HEAP]->{readwrite};
print "CHILD: call to $function() failed: $error.\n" if $error;
}sub accept_failed {
my ($function, $error) = @_[ARG0, ARG2]; delete $_[HEAP]->{listener};
print "SERVER: Call to $function() failed: $error.\n";
}sub server_stop {
print "SERVER: Stopped.\n";
}SAMPLE OUTPUT:
SERVER: Started listening on port 31008. CHILD: Connected to 127.0.0.1:51687. SERVER: Got connection from 127.0.0.1:51687. Thu Jun 5 15:31:06 2003 CHILD: Got input from peer 3: "9" (9). Thu Jun 5 15:31:06 2003 CHILD: Got input from peer 3: "10" (19). Thu Jun 5 15:31:07 2003 CHILD: Got input from peer 3: "6" (25). Thu Jun 5 15:31:08 2003 CHILD: Got input from peer 3: "2" (27). Thu Jun 5 15:31:08 2003 CHILD: Got input from peer 3: "7" (34). Thu Jun 5 15:31:09 2003 Removed 34 from register 3. Thu Jun 5 15:31:09 2003 CHILD: Got input from peer 3: "9" (9). Thu Jun 5 15:31:10 2003 CHILD: Got input from peer 3: "3" (12). Thu Jun 5 15:31:10 2003 CHILD: Got input from peer 3: "1" (13). Thu Jun 5 15:31:11 2003 CHILD: Got input from peer 3: "5" (18). Thu Jun 5 15:31:11 2003 CHILD: Got input from peer 3: "7" (25). Thu Jun 5 15:31:12 2003 Removed 25 from register 3. Thu Jun 5 15:31:12 2003 CHILD: Got input from peer 3: "9" (9). Thu Jun 5 15:31:13 2003 CHILD: Got input from peer 3: "5" (14). Thu Jun 5 15:31:14 2003 CHILD: Got input from peer 3: "8" (22). Thu Jun 5 15:31:14 2003 CHILD: Got input from peer 3: "8" (30). Thu Jun 5 15:31:15 2003 Removed 30 from register 3. Thu Jun 5 15:31:18 2003 Removed 0 from register 3. Thu Jun 5 15:31:21 2003 Removed 0 from register 3. ^CCHILD: Stopped. Totals: Actual: 89, Register: 0. SERVER: Stopped.
