POE::Component::Server::TCP - a simplified TCP server |
POE::Component::Server::TCP - a simplified TCP server
use POE qw(Component::Server::TCP);
### First form just accepts connections.
my $acceptor_session_id = POE::Component::Server::TCP->new( Port => $bind_port, Address => $bind_address, # Optional. Hostname => $bind_hostname, # Optional. Domain => AF_INET, # Optional. Alias => $session_alias, # Optional. Acceptor => \&accept_handler, Error => \&error_handler, # Optional. );
### Second form also handles connections.
my $acceptor_session_id = POE::Component::Server::TCP->new( Port => $bind_port, Address => $bind_address, # Optional. Hostname => $bind_hostname, # Optional. Domain => AF_INET, # Optional. Alias => $session_alias, # Optional. Error => \&error_handler, # Optional. Args => [ "arg0", "arg1" ], # Optional. Concurrency => -1, # Optional.
SessionType => "POE::Session::Abc", # Optional. SessionParams => [ options => { debug => 1 } ], # Optional.
ClientInput => \&handle_client_input, # Required. ClientConnected => \&handle_client_connect, # Optional. ClientDisconnected => \&handle_client_disconnect, # Optional. ClientError => \&handle_client_error, # Optional. ClientFlushed => \&handle_client_flush, # Optional. ClientFilter => POE::Filter::Xyz->new()", # Optional. ClientInputFilter => POE::Filter::Xyz->new(), # Optional. ClientOutputFilter => POE::Filter::Xyz->new(), # Optional. ClientShutdownOnError => 0, # Optional.
# Optionally define other states for the client session. InlineStates => { ... }, PackageStates => [ ... ], ObjectStates => [ ... ], );
### Call signatures for handlers.
sub accept_handler { my ($socket, $remote_address, $remote_port) = @_[ARG0, ARG1, ARG2]; }
sub error_handler { my ($syscall_name, $error_number, $error_string) = @_[ARG0, ARG1, ARG2]; }
sub handle_client_input { my $input_record = $_[ARG0]; }
sub handle_client_error { my ($syscall_name, $error_number, $error_string) = @_[ARG0, ARG1, ARG2]; }
sub handle_client_connect { # no special parameters }
sub handle_client_disconnect { # no special parameters }
sub handle_client_flush { # no special parameters }
### Reserved HEAP variables:
$heap->{listener} = SocketFactory (only Acceptor and Error callbacks) $heap->{client} = ReadWrite (only in ClientXyz callbacks) $heap->{remote_ip} = remote IP address in dotted form $heap->{remote_port} = remote port $heap->{remote_addr} = packed remote address and port $heap->{shutdown} = shutdown flag (check to see if shutting down) $heap->{shutdown_on_error} = Automatically disconnect on error.
### Accepted public events.
# Start shutting down this connection. $kernel->yield( "shutdown" );
# Stop listening for connections. $kernel->post( server => "shutdown" );
# Set the maximum number of simultaneous connections. $kernel->call( server => set_concurrency => $count );
### Responding to a client.
$heap->{client}->put(@things_to_send);
The TCP server component hides a generic TCP server pattern. It uses POE::Wheel::SocketFactory and POE::Wheel::ReadWrite internally, creating a new session for each connection to arrive.
The authors hope that generic servers can be created with as little work as possible. Servers with uncommon requirements may need to be written using the wheel classes directly. That isn't terribly difficult. A tutorial at http://poe.perl.org/ describes how.
new()
method can accept quite a lot of parameters. It will return
the session ID of the accecptor session. One must use callbacks to
check for errors rather than the return value of new().
POE::Component::Server::TCP supplies common defaults for most callbacks and handlers.
The coderef receives its parameters directly from SocketFactory's SuccessEvent. ARG0 is the accepted socket handle, suitable for giving to a ReadWrite wheel. ARG1 and ARG2 contain the packed remote address and numeric port, respectively. ARG3 is the SocketFactory wheel's ID.
Acceptor => \&accept_handler
Acceptor lets programmers rewrite the guts of Server::TCP entirely. It is not compatible with the /^Client/ callbacks.
Address => '127.0.0.1' # Localhost IPv4 Address => "::1" # Localhost IPv6
It's passed directly to SocketFactory's BindAddress parameter, so it can be in whatever form SocketFactory supports. At the time of this writing, that's a dotted quad, an IPv6 address, a host name, or a packed Internet address. See also the Hostname parameter.
Alias => 'chargen'
Later on, the 'chargen' service can be shut down with:
$kernel->post( chargen => 'shutdown' );
Args
constructor parameter, as ARG0.
The ClientConnected callback will not be called within the same session context twice.
ClientDisconnected callbacks receive the usual POE parameters, but nothing special is included.
It receives POE's usual error handler parameters: ARG0 is the name of the function that failed. ARG1 is the numeric failure code ($! in numeric context). ARG2 is the string failure code ($! in string context), and so on.
POE::Wheel::ReadWrite discusses the error parameters in more detail.
A default error handler will be provided if ClientError is omitted. The default handler will log most errors to STDERR.
The value of ClientShutdownOnError determines whether the connection will be shutdown after errors are received. It is the client shutdown, not the error, that invokes ClientDisconnected callbacks.
It can take a class name, an arrayref, or a POE::Filter object.
If ClientFilter contains a SCALAR, it defines the name of the POE::Filter class. Default constructor parameters will be used to create instances of that filter.
ClientFilter => "POE::Filter::Stream",
If ClientFilter contains a list reference, the first item in the list will be a POE::Filter class name, and the remaining items will be constructor parameters for the filter. For example, this changes the line separator to a vertical bar:
ClientFilter => [ "POE::Filter::Line", Literal => "|" ],
If ClientFilter contains an object, it will have a clone method called on it each time a client connects.
ClientFilter => POE::Filter::Block->new()
ClientFilter is optional. The component will use ``POE::Filter::Line'' if it is omitted.
If you supply a different value for Filter, then you must also use
that filter class.
Usage is the same as ClientFilter.
ClientInputFilter => [ "POE::Filter::Line", Literal => "|" ], ClientOutputFilter => "POE::Filter::Stream", ClientInputFilter => POE::Filter::Block->new(),
ClientInput => \&input_handler
ClientInput and Acceptor are mutually exclusive. Enabling one prohibits the other.
If this option is turned off, it becomes your responsibility to deal with client errors properly. Not handling them, or not destroying wheels when they should be, will cause the component to spit out a constant stream of errors, eventually bogging down your application with dead connections that spin out of control.
You've been warned.
Note: AF_INET6 and PF_INET6 are supplied by the Socket6 module, which is available on the CPAN. You must have Socket6 loaded before POE::Component::Server::TCP will create IPv6 sockets.
A default error handler will be provided if Error is omitted. The default handler will log the error to STDERR and shut down the server. Active connections will have the opportunity to complete their transactions.
Port => 30023
SessionParams => [ options => { debug => 1, trace => 1 } ],
It is important to realize that some of the arguments to SessionHandler may get clobbered when defining them for your SessionHandler. It is advised that you stick to defining arguments in the ``options'' hash such as trace and debug. See the POE::Session manpage for an example list of options.
SessionType => "POE::Session::MultiDispatch"
SessionType is optional. The component will create POE::Session instances if a new type isn't specified.
Started is optional.
set_concurrency
event, see EVENTS.
Note that if you define the Acceptor
callback, you will have to inform
the TCP server session that a connection was closed. This is done by sending
a disconnected
event to your session's parent. This is only necessary if
you define an Acceptor
callback. For ClientInput
, it's all handled
for you.
Example:
Acceptor => sub { # .... POE::Session->create( # .... inline_states => { _start => sub { # .... # remember who our parent is $_[HEAP]->{server_tcp} = $_[SENDER]->ID; # .... }, got_client_disconnect => sub { # .... $_[KERNEL]->post( $_[HEAP]->{server_tcp} => 'disconnected' ); # .... } } ); }
It's possible to manipulate a TCP server component by sending it messages.
Active connections are not shut down until they disconnect.
Concurrency
is set and you are using an Acceptor callback.
$kernel->call( "tcp_server_alias", "set_concurrency", $max_count );
POE::Component::Client::TCP, POE::Wheel::SocketFactory, POE::Wheel::ReadWrite, POE::Filter
This looks nothing like what Ann envisioned.
This component currently does not accept many of the options that POE::Wheel::SocketFactory does.
This component will not bind to several addresses at once. This may be a limitation in SocketFactory, but it's not by design.
This component needs more complex error handling which appends for construction errors and replaces for runtime errors, instead of replacing for all.
Some use cases require different session classes for the listener and the connection handlers. This isn't currently supported. Please send patches. :)
POE::Component::Server::TCP is Copyright 2000-2006 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.
POE::Component::Server::TCP is based on code, used with permission, from Ann Barcomb <kudra@domaintje.com>.
POE::Component::Server::TCP is based on code, used with permission, from Jos Boumans <kane@cpan.org>.
POE::Component::Server::TCP - a simplified TCP server |