Skip to content
Browse files

Added P::C::Server::TCP

  • Loading branch information...
1 parent 5f17382 commit aa9ed4dbddc22e7992ac727925a442e98af62be9 @rcaputo committed
Showing with 232 additions and 9 deletions.
  1. +5 −1 Changes
  2. +1 −0 MANIFEST
  3. +2 −1 README
  4. +44 −0 lib/POE/Component.pm
  5. +165 −0 lib/POE/Component/Server/TCP.pm
  6. +15 −7 tests/01_sessions.t
View
6 Changes
@@ -27,7 +27,7 @@ Removed the place-holder test that suggested people trie the samples
directory.
Added t/01_sessions.t to test sessions (new and inline create) and
-basic events (post and yield);
+basic events (post, yield and call);
Added t/02_alarms.t to test delayed events (alarm, delay, alarm_add
and delay_add).
@@ -39,6 +39,10 @@ Added POE::Kernel::(alarm|delay)_add to post additional alarms to a
particular state. Unlike POE::Kernel::(alarm|delay), these don't
clear existing alarms for the destination state.
+Kicked off the POE::Component heirarchy with
+POE::Component::Server::TCP (POE::Component is frequently abbreviated
+as P::C in conversation but not in code).
+
0.0907 2000.03.02
-----------------
View
1 MANIFEST
@@ -6,6 +6,7 @@ POE.pm
POE/Attribute/Array.pm
POE/Attribute/Hash.pm
POE/Attribute/Scalar.pm
+POE/Component/Server/TCP.pm
POE/Curator.pm
POE/Driver.pm
POE/Driver/SysRW.pm
View
3 README
@@ -11,7 +11,8 @@ Testing; The Future
ABOUT POE
=========
-"POE" is an acronym for Perl Object Environment.
+"POE" is an acronym for Perl Object Environment. This may change to
+Persistent Object Environment.
First and foremost, it is a programming framework for event-driven
state machines.
View
44 lib/POE/Component.pm
@@ -0,0 +1,44 @@
+# $Id$
+# Copyrights and documentation are after __end__.
+
+package POE::Component;
+
+use strict;
+
+sub new {
+ my $type = shift;
+ croak "$type is not meant to be used directly";
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+POE::Component - POE Stand-Alone Sessions
+
+=head1 SYNOPSIS
+
+Varies from component to component.
+
+=head1 DESCRIPTION
+
+POE components are sessions that have been designed as stand-alone
+modules. They tend to be interfaced through POE::Kernel::post() or
+call(), but this is not a formal convention.
+
+The POE::Component namespace was started to provide a place for others
+publish their POE modules without requiring coordination with the main
+POE distribution.
+
+=head1 BUGS
+
+The POE::Component namespace should probably be coordinated, but who
+has time for that?
+
+=head1 AUTHORS & COPYRIGHTS
+
+Please see the POE manpage or manpages for specific components.
+
+=cut
View
165 lib/POE/Component/Server/TCP.pm
@@ -0,0 +1,165 @@
+# $Id$
+
+package POE::Component::Server::TCP;
+
+use Carp qw(carp croak);
+use vars qw($VERSION);
+
+$VERSION = 1.00;
+
+# Explicit use to import the parameter constants.
+use POE::Session;
+
+# Create the server. This is just a handy way to encapsulate
+# POE::Session->create(). Because the states are so small, it uses
+# real inline coderefs.
+
+sub new {
+ my $type = shift;
+
+ # Helper so we don't have to type it all day. $mi is a name I call
+ # myself.
+ my $mi = $type . '->new()';
+
+ # If they give us lemons, tell them to make their own damn
+ # lemonade.
+ croak "$mi requires an even number of parameters" if (@_ & 1);
+ my %param = @_;
+
+ # Validate what we're given.
+ croak "$mi needs a Port parameter" unless exists $param{Port};
+ croak "$mi needs an Acceptor parameter" unless exists $param{Acceptor};
+
+ # Extract parameters.
+ my $port = delete $param{Port};
+ my $accept_callback = delete $param{Acceptor};
+ my $error_callback = delete $param{Error};
+
+ # Complain about strange things we're given.
+ foreach (sort keys %param) {
+ carp "$mi doesn't recognize \"$_\" as a parameter";
+ }
+
+ # Create the session, at long last.
+
+ POE::Session->new
+
+ # The POE::Session has been set up. Create a listening socket
+ # factory which will call back $callback with accepted client
+ # sockets.
+ ( _start =>
+ sub {
+ $_[HEAP]->{listener} = POE::Wheel::SocketFactory->new
+ ( BindPort => $port,
+ Reuse => 'yes',
+ SuccessState => 'got_connection',
+ FailureState => 'got_error',
+ );
+ },
+
+ # Catch an error.
+ got_error => ( defined($error_callback)
+ ? $error_callback
+ : \&default_error_handler
+ ),
+
+ # We accepted a connection. Do something with it.
+ got_connection => $accept_callback,
+ );
+
+ # Return undef so nobody can use the POE::Session reference. This
+ # isn't very friendly, but it saves grief later.
+ undef;
+}
+
+# The default error handler logs to STDERR and shuts down the server.
+sub default_error_handler {
+ warn( 'Server ', $_[SESSION]->ID,
+ " got $_[ARG0] error $_[ARG1] ($_[ARG2])\n"
+ );
+ delete $_[HEAP]->{listener};
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+POE::Component::Server::TCP - simplified TCP server
+
+=head1 SYNOPSIS
+
+ use POE;
+
+ sub accept_handler {
+ my ($socket, $remote_address, $remote_port) = @_[ARG0, ARG1, ARG2];
+ # code goes here to handle the accepted socket
+ }
+
+ sub error_handler {
+ my ($op, $errnum, $errstr) = @_[ARG0, ARG1, ARG2];
+ warn "server encountered $op error $errnum: $errstr";
+ # possibly shut down the server
+ }
+
+ new POE::Component::Server::TCP
+ ( Port => $bind_port,
+ Acceptor => \&accept_handler,
+ Error => \&error_handler, # Optional.
+ );
+
+=head1 DESCRIPTION
+
+POE::Component::Server::TCP is a wrapper around
+POE::Wheel::SocketFactory. It abstracts the steps required to create
+a TCP server, taking away equal measures of responsibility and control
+for listening for and accepting remote socket connections.
+
+At version 1.0, the Server::TCP component takes three arguments:
+
+=over 2
+
+=item *
+
+Port
+
+Port is the port the listening socket will be bound to.
+
+=item *
+
+Acceptor
+
+Acceptor is a coderef which will be called to handle accepted sockets.
+The coderef is used as POE::Wheel::SocketFactory's SuccessState, so it
+accepts the same parameters.
+
+=item *
+
+Error
+
+Error is an optional coderef which will be called to handle server
+socket errors. The coderef is used as POE::Wheel::SocketFactory's
+FailureState, so it accepts the same parameters. If it is omitted, a
+fairly standard error handler will be provided. The default handler
+will log the error to STDERR and shut down the server.
+
+=back
+
+=head1 SEE ALSO
+
+POE::Wheel::SocketFactory
+
+=head1 BUGS
+
+POE::Component::Server::TCP does not accept many of the options that
+POE::Wheel::SocketFactory does.
+
+=head1 AUTHORS & COPYRIGHTS
+
+POE::Component::Server::TCP is Copyright 2000 by Rocco Caputo. All
+rights are reserved. POE::Component::Server::TCP is free software,
+and it may be redistributed and/or modified under the same terms as
+Perl itself.
+
+=cut
View
22 tests/01_sessions.t
@@ -27,7 +27,8 @@ sub task_start {
sub task_run {
my ($kernel, $session, $heap, $id) = @_[KERNEL, SESSION, HEAP, ARG0];
- if (++$heap->{count} < $event_count) {
+
+ if ( $kernel->call( $session, next_count => $id ) < $event_count ) {
if ($heap->{count} & 1) {
$kernel->yield( count => $id );
@@ -42,6 +43,11 @@ sub task_run {
}
}
+sub task_next_count {
+ my ($kernel, $session, $heap, $id) = @_[KERNEL, SESSION, HEAP, ARG0];
+ ++$heap->{count};
+}
+
sub task_stop {
$completions[$_[HEAP]->{id}] = $_[HEAP]->{count};
}
@@ -57,9 +63,10 @@ for (my $i=0; $i<$machine_count; $i++) {
if ($i & 1) {
POE::Session->create
( inline_states =>
- { _start => \&task_start,
- _stop => \&task_stop,
- count => \&task_run,
+ { _start => \&task_start,
+ _stop => \&task_stop,
+ count => \&task_run,
+ next_count => \&task_next_count,
},
args => [ $i ],
);
@@ -68,9 +75,10 @@ for (my $i=0; $i<$machine_count; $i++) {
# Even instances, try POE::Session->new
else {
POE::Session->new
- ( _start => \&task_start,
- _stop => \&task_stop,
- count => \&task_run,
+ ( _start => \&task_start,
+ _stop => \&task_stop,
+ count => \&task_run,
+ next_count => \&task_next_count,
[ $i ],
);
}

0 comments on commit aa9ed4d

Please sign in to comment.
Something went wrong with that request. Please try again.