NAME

POE::Component::Client::TCPMulti

SYNOPSIS

POE::Component::Client::TCPMulti->new
( InputEvent   => sub {
      $_[KERNEL]->yield(send => $_[CHEAP]->ID, "Some Stuff");
  },

  Initialize   => \&InitWierdness,
  ErrorEvent   => \&ErrorHandle,   
  Disconnected => \&ErrorHandle,   
  TimeoutEvent => \&TimeoutHandle,
  FailureEvent => \&FailureHandle,
  SuccessEvent => \&SuccessHandle,

  Domain       => AF_INET,     # Optional

  Alias        => "MySession", # Optional
  Timeout      => 30,          # Seconds, Optional
  Filter       => "POE::Filter::Something", # Optional

  inline_states => {
      _start => sub {
          $_[KERNEL]->yield(connect => q(127.0.0.1), 25);
      },
  },
  
  args => $Session_Args                # Optional
  object_states => $Object_States      # Optional
  package_states => $Package_States    # Optional

);

DESCRIPTION

POE::Component::Client::TCPMulti is a very lightweight, highly optimized component designed for large numbers of simultanious outgoing connections. The major advantage to this module over POE::Component::Client::TCP is that it runs in a single session, reguardless of the number of outgoing simultanious connections. I have found this in fact to use considerable less overhead than POE::Component::Client::TCP in high traffic. The disadvantage lies mearly in the API complexity over POE::Component::Client::TCP.

It is in fact due to this added API complexity that I decided to create a seperate module, rather than altering POE::Component::Client::TCP [ or coaxing Rocco to let me ]. POE::Component::Client::TCP is a great module and this is not designed to completely replace it. It is however designed as a solution for extremely high traffic situations when the overhead of an individual session for each outgoing connection is not appropriate for the added simplicity in the API. Especially considering that this API is not really *that* much more complex.

Over all I tried as hard as possible to make crossing your application over from POE::Component::Client::TCP as simple as possible.

CONSTRUCTOR PARAMETERS

SuccessEvent

SuccessEvent, takes a CODE reference as a parameter, and is the event which will be called after a connection attempt has decidedly been successful. (See POE::Wheel::SocketFactory)

"ARG0" will hold the new socket handle, which you
         should never actually need.
"ARG1" will hold the sockets remote address, which is packed.
         You will need to use inet_ntoa() (See L<Socket>)
         if a human readable version is neccesary.
"ARG2" will hold the sockets remote port.
"ARG3" holds the OLD id for the connection.
"ARG4" holds the NEW id for the connection, 
         synonymous with $_[CHEAP]->ID
FailureEvent

FailureEvent, takes a CODE references as a parameter. FailureEvent will be called when a socket error occurs while attempting to create the connection. (See POE::Wheel::SocketFactory)

"ARG0" contains the name of the operation that failed.
"ARG1" and "ARG2" hold numeric and string 
         values describing the error.
"ARG3" contains the Wheel's unique ID,
         synonymous with $_[CHEAP]->ID 
         
ErrorEvent

ErrorEvent, takes a CODE reference as a parameter. It is the event that will be called after a connection has been successfull, but has closed unexpectedly. (See POE::Wheel::ReadWrite)

"ARG0" contains the name of the operation that failed.  
         This is not a function name, but an action 
         (usually 'read').
"ARG1" and "ARG2" hold numeric and string 
         values describing the error.
"ARG3" contains the connections unique ID,
         again synonymous with $_[CHEAP]->ID
Disconnected

Disconnected takes a CODE reference, and is the event taht will be called after a shutdown event was succesfull. This only affects connection closures requested by your program.

TimeoutEvent

TimeoutEvent takes a CODE reference, and is the event that will be called when a connection has been idle for longer than the specified value of Timeout. (See Timeout below) When this event occurs, Disconnected will not be called.

Initialize

Initialization is wierdness. Its designed to replace '_start' in multisession applications. Its simply called, is only here for integration convience, and will eventually be depriciated. ( It is after all, something of a hack ). Basically in ::Client::TCP applications, many people use _start at the begining of thier session to do various initialization for thier connection. This is what you would use until you finished making a ::Client::TCPMulti application out of your ::Client::TCP application. I dont suggest using it anything more than temporarily, it is very likely to not exist in future versions.

inline_states

inline_states will actually create inline states with 3 exceptions, _start, _child and _end inline states, and any inline state named "connect", "shutdown", "send", or "die" will be overwritten. However, _start, _child, or _end inline states will be called during _start, _child, and _end appropriately, only prior to ::Client::TCPMulti completing its own internal tasks for these times. I cant really see any reason for using _child within the session this component creates, but you never know :) If you're trying to figure out why your _start only gets called once, see Initialization is wierdness, above.

object_states

object_states will be passed on to the created POE::Session, and is expected to be an ARRAY ref. (See POE::Session)

package_states

package_states will be passed on to the created POE::Session, and is expected to be an ARRAY ref. (See POE::Session)

options

options describes the options to be set for the created POE::Session, and is expected to be a hashref. (See POE::Session). Useful options are commonly trace and assert, which turn on trace and assertion debug output for the session:

options => { trace => 1, assert => 1 },

args

args will be passed on to the created POE::Session, and is expected to be an ARRAY ref. The value of args will be passed on to the _start state of your code. (See POE::Session)

Timeout

Timeout takes a integer as a parameter, and is the value in seckonds in which each connection's timeout alarm will be executed if there is no incoming data from the connection. The default is 30 seconds.

Alias

Alias takes a string as a parameter, which will be the alias for the session this component creates. (See POE::Session)

INLINE STATES

This component defines a number of inline states which cannot be overridden. They are used as part of the API, for performing tasks that were handled in the constructor of ::Client::TCP, as well as a few which are predefined for convenience.

connect

The "connect" state creates a new connection to the specified remote address and port, using the optionally specified local address and port. It can be posted to, yielded, or called just as a normal inline state would be. The syntax for such would be something like:

$_[KERNEL]->yield(connect => $ip, $port, $BindIP, $BindPort);
where $BindIP and $BindPort are optional.
send

The "send" state appends data to a connections queue for sending. It is almost exactly the same as the "send" state used in the POE Cookbook. It takes a connection id, and data as an arguement. The suggested syntax for it would be like:

$_[KERNEL]->yield(send => $_[CHEAP]->ID, "some data");
shutdown

The "shutdown" state attempts to close a connection gracefully. It is the same as the "shutdown" state for ::Client::TCP. It takes a connection id as an arguement, the suggest syntax is something like:

$_[KERNEL]->yield(shutdown => $_[CHEAP]->ID);
die

The "die" state attempts to close all open connections gracefully, ending the session. It takes no arguements:

$_[KERNEL]->yield("die");

OPTIMIZATIONS

This module has a number of optimizations, as it is in fact designed for extremely high traffic situations, and easy migration from ::Client::TCP.

Event Routing

All component event routing is done independantly of POE::Kernel. While it is true that POE::Kernel is extremely fast, and very light weight, it is already issuing the events to this Components inline states. So while it is a common practice to use POE::Kernel for Component Event routing, it has been opted against. Its just extra overhead, and each of this module's inline states are extremely low in overhead, so all event routing is done completely aside from any event queue. The event queue is used to issue the intial event.

Alot of testing has proven this to actually create a faster runtime without reducing responsive time of POE. In fact, in most instances it was greatly increased since less work was put in the event queue uneccesarily.

Localized Heap

The $_[CHEAP] your event states will recieve is slightly magical. This was done namely as a migration route for applications designed using ::Client::TCP. Each *connection* has its own internal heap, which can be accessed via $_[CHEAP]. This was provided as a solution to each connection not having its own session, and in turn, its own $_[HEAP]. Events that do not go through the component will have a $_[CHEAP] which is undefined. So if you want it, you will have to fetch it (Or just store a $_[CHEAP] reference for each connection in your $_[HEAP]). See fetchCHEAP for fetching the $_[CHEAP].

Again, yes, you can use $_[CHEAP] as a "normal" heap. It will contain elements with special meanings, but they are all prefixed with ``TM_''.

CHEAP magic

$_[CHEAP] has other magic aside from being a localized heap, it is a blessed reference with several methods. Some of these are replacement for Session-Wise methods you would usually use to identify your current connection in the ::Client::TCP component. Others, are for directly modifying your ReadWrite wheel to do things that aren't possible in ::Client::TCP [ but I needed, so you get the features :D ].

CHEAP Methods

$_[CHEAP]->ID

The ``ID'' method returns the current ID of the current connection. I would not rely on this being static, but if you need to use it for some kind of internal indexing, just pay mind to the fact that your ID will change after the connection was successful. The reason for this is that the Wheel ID is used for connection indexing by ::Client::TCPMulti.

$_[CHEAP]->ADDR

Unlike ::Client::TCP, ::Client::TCPMulti keeps track of information about your connection for you. So yes, you can go through and delete a bunch of that code. The ``ADDR'' method returns the address you are connecting or connected to, in Local Short IP notation (255.255.255.255).

$_[CHEAP]->PORT

The ``PORT'' method returns the PORT you are connected to, as an integer.

$_[CHEAP]->filter("POE::Filter::Something", Option => "value");

``filter'' is a very special method for CHEAP, it lets you change the filter the current connection is currently using, in real time. You must 'use' or 'require' the Filter module somewhere in your code if you want to use it (unless its POE::Filter::Line).

$_[CHEAP]->event() - Removed

This method has been removed. If you need to change an event, I suggest you make the first statement in your event handler reroute the request based a $_[CHEAP] element.

VARIABLES

DEBUG

The ``DEBUG'' variable will enable warnings for each Connect, Disonnect, Timeout etc. These are indexed by Connection ID. While you can turn on session assertions, since we only use one session I've found them difficult to use for debugging applications written with this module.

Enabling this:

use POE qw(Component::Client::TCPMulti);

$POE::Component::Client::TCPMulti::DEBUG++;
VERSION

The ``VERSION'' variable is a constant, that holds this components version number.

BUGS

Probably tons, let me know if you find any.

AUTHOR

Scott S. McCoy

Scott S. McCoy is (tag@cpan.org)

Thanks to Rocco Caputo, author of POE.

This software is released under the BEERWARE license, a free software license.

The End

3 POD Errors

The following errors were encountered while parsing the POD:

Around line 601:

You forgot a '=back' before '=head4'

Around line 608:

'=item' outside of any '=over'

Around line 639:

You forgot a '=back' before '=head1'