Creating and shutting down POE::Sessions
Hi, my baby steps in the land of POE: I have tried to setup a small application that would listen on a TCP port and get commands 'start' and 'stop', When receiving start it should create a new POE::Session to count. When receiving stop it should stop the counting and destroy that POE::Session. It seems I managed to do it but I'd be glad to receive comments about the code: #!/usr/bin/perl use warnings; use strict; use 5.010; use POE qw(Component::Server::TCP); my $port = 12345; print "telnet to $port\n"; my $session_id; POE::Component::Server::TCP->new( Port=> $port, ClientInput => \&client_input, ClientConnected => \&client_connected, ); POE::Kernel->run(); exit; sub counter { #print "counter\n"; return if not $_[HEAP]{run}; $_[HEAP]{count}++; #$_[HEAP]{client}->put("Count: $_[HEAP]"); print "Count: $_[HEAP]{count}\n"; $_[KERNEL]->delay('counter' => 1); } sub session_start { print "session_start\n"; print "session kernel: $_[KERNEL]\n"; $_[HEAP]{count} = 0; $_[HEAP]{run} = 1; $_[KERNEL]->yield('counter'); print "after calling yield\n"; } sub session_stop { print "session_stop\n"; } sub stop_session { $_[HEAP]{run} = 0; } sub client_input { my ($heap, $input) = @_[HEAP, ARG0]; if ($input eq 'start') { $session_id = POE::Session->create( inline_states => { _start => \&session_start, _stop => \&session_stop, counter => \&counter, stop_session => \&stop_session, } )->ID; print "kernel: $_[KERNEL]\n"; print "SID: $session_id\n"; } elsif ($input eq 'stop') { print "stop received\n"; if ($session_id) { $_[KERNEL]->post( $_[KERNEL]->ID_id_to_session($session_id), 'stop_session' ); $session_id = undef; } print "stop done\n"; } else { $_[HEAP]{client}->put("Invalid command '$input'"); } return; } sub client_connected { print "connected\n"; $_[HEAP]{client}->put("type 'start' or 'stop':"); }; -- Gabor Szabo http://szabgab.com/
Re: Creating and shutting down POE::Sessions
On May 18, 2011, at 09:30, Gabor Szabo wrote: > Hi, > > my baby steps in the land of POE: > > I have tried to setup a small application that would listen on a TCP > port and get commands 'start' and 'stop', > When receiving start it should create a new POE::Session to count. > When receiving stop it should stop the counting and destroy that > POE::Session. It seems I managed to do it but I'd be glad to receive > comments about the code: [code removed] Hi, Gabor. Please see the revised code below. The major change was to eliminate the counting session. They didn't seem necessary, and their presence just complicated things. #!/usr/bin/perl use warnings; use strict; use 5.010; use POE qw(Component::Server::TCP); my $port = 12345; print "telnet to $port\n"; my $session_id; POE::Component::Server::TCP->new( Port=> $port, ClientInput => \&client_input, ClientConnected => \&client_connected, # These event handlers are registered for each client connection. # Each client connection has its own session, heap, etc. InlineStates => { count => \&client_count, }, ); POE::Kernel->run(); exit; sub client_input { my ($kernel, $heap, $input) = @_[KERNEL, HEAP, ARG0]; print "client input: $input\n"; if ($input eq 'start') { $heap->{counter} = 0; $kernel->yield('count'); return; } if ($input eq 'stop') { delete $heap->{counter}; return; } $heap->{client}->put("Invalid command '$input'"); return; } sub client_connected { $_[HEAP]{client}->put("type 'start' or 'stop':"); } sub client_count { my ($kernel, $heap) = @_[KERNEL, HEAP]; # Deleted when the counter stops. return unless exists $heap->{counter}; # Set when this connection is shutting down. return if $heap->{shutdown}; print "Counter: ", ++$heap->{counter}, "\n"; $kernel->delay(count => 1); } -- Rocco Caputo
Re: Creating and shutting down POE::Sessions
On Thu, May 19, 2011 at 5:28 AM, Rocco Caputo wrote: > On May 18, 2011, at 09:30, Gabor Szabo wrote: > >> Hi, >> >> my baby steps in the land of POE: >> >> I have tried to setup a small application that would listen on a TCP >> port and get commands 'start' and 'stop', >> When receiving start it should create a new POE::Session to count. >> When receiving stop it should stop the counting and destroy that >> POE::Session. It seems I managed to do it but I'd be glad to receive >> comments about the code: > > > [code removed] > > Hi, Gabor. Please see the revised code below. The major change was to > eliminate the counting session. They didn't seem necessary, and their > presence just complicated things. > Hi Rocco, thanks for your reply. That looks indeed more simple. Reading again the documentation, do I understand correctly that already the ClientConnected and ClientInput are callbacks of the individual, connection related POE::Session? Further working on the application I am writing, I'll need to have several counters and keep the counters work even after the original requester disconnected. Trying with one, in my example it worked as the counter Session was not related to the connection. I wonder if in your solution, can I tell the session to remain active even after the user disconnected? Can I also remove it from the concurrency counter? Would in this case the separate POE::Session work better? regards Gabor
Re: Creating and shutting down POE::Sessions
On May 19, 2011, at 03:18, Gabor Szabo wrote: > On Thu, May 19, 2011 at 5:28 AM, Rocco Caputo wrote: >> On May 18, 2011, at 09:30, Gabor Szabo wrote: >> >>> I have tried to setup a small application that would listen on a TCP >>> port and get commands 'start' and 'stop', >>> When receiving start it should create a new POE::Session to count. >>> When receiving stop it should stop the counting and destroy that >>> POE::Session. It seems I managed to do it but I'd be glad to receive >>> comments about the code: >> >> [code removed] >> >> Hi, Gabor. Please see the revised code below. The major change was to >> eliminate the counting session. They didn't seem necessary, and their >> presence just complicated things. > > thanks for your reply. That looks indeed more simple. Reading again > the documentation, > do I understand correctly that already the ClientConnected and > ClientInput are callbacks of > the individual, connection related POE::Session? Yes, all the /^Client/ callbacks are for individual connection related POE::Session instances. > Further working on the application I am writing, I'll need to have > several counters > and keep the counters work even after the original requester disconnected. > Trying with one, in my example it worked as the counter Session was not > related > to the connection. > I wonder if in your solution, can I tell the session to remain active > even after > the user disconnected? Can I also remove it from the concurrency counter? > > Would in this case the separate POE::Session work better? Yes. I assume your independent counters have names. I've attached a revised design to account for multiple named timers. Since the code's getting larger, I modularized it a bit, making it even larger still. Sample output: 1) macbookpoe:~% nc localhost 12345 Type 'start', 'stop', or 'list': list No known counters. start aaa Starting counter aaa... start bbb Starting counter bbb... start ccc Starting counter ccc... list Known counters at Sun May 22 01:56:51 2011: aaa:30152, bbb:13406, ccc:3525 stop bbb Stopping counter bbb... list Known counters at Sun May 22 01:56:54 2011: aaa:50326, ccc:23699 ^C 1) macbookpoe:~% nc localhost 12345 Type 'start', 'stop', or 'list': list Known counters at Sun May 22 01:56:57 2011: aaa:70739, ccc:44112 ^C -- Rocco Caputo #!/usr/bin/perl use warnings; use strict; use 5.010; use POE qw(Component::Server::TCP); { package Counter; use warnings; use strict; use POE; # For KERNEL, HEAP, ARG0, etc. my %counter; # Spawn the Counter session. # There may be only one due to the scoping of %counter. # # A design incorporating multiple Counter sessions would imply each # had its own counter namespace. I'd use $_[HEAP]{counter} in that # case. # # But for now I'm using %counter in closures to simplify the code. sub spawn { POE::Session->create( inline_states => { _start => sub { # The alias is sufficient to keep this session # around as long as other sessions exist. $_[KERNEL]->alias_set("counter"); }, count => sub { my ($kernel, $counter_name) = @_[KERNEL, ARG0]; # The counter was deleted in stop_counter? # By returning here, we stop perpetuating the recursive # yield() that drives this counter. return unless exists $counter{$counter_name}; print "Counter $counter_name = ", ++$counter{$counter_name}, "\n"; # The yield() here perpetuates the counter. $kernel->yield( count => $counter_name ); }, start_counter => sub { my ($kernel, $counter_name) = @_[KERNEL, ARG0]; # Don't start a counter that's already running. return if exists $counter{$counter_name}; $counter{$counter_name} = 0; $kernel->yield( count => $counter_name ); }, stop_counter => sub { my ($kernel, $counter_name) = @_[KERNEL, ARG0]; # Don't stop a counter that's not running. return unless exists $counter{$counter_name}; # Deleting the counter stops it. delete $counter{$counter_name}; }, }, ); } # These subs that follow are plain class methods. # # I've put the POE callbacks into anonymous coderefs above to keep # them visually distinct from plain methods. I often also use # prefixes like _poe_foo() to indicate private POE callbacks. sub start { my ($class, $counter_name) = @_; # start() passes a message from the client connection session to # the counter session. The counters run in a dedicated session # separate from each connection, so connections can come and go # independently from counters. $poe_kernel->post( counter => start_counter => $counter_name ); } sub stop { my ($class, $counter_name) = @_; delete $counter{$counter_name}; } sub list { return %counter; } } ### Abstract t