Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

How do I close a POE SocketFactory Socket?

by Declarent (Sexton)
on Jun 24, 2002 at 22:33 UTC ( #176971=perlquestion: print w/replies, xml ) Need Help??
Declarent has asked for the wisdom of the Perl Monks concerning the following question:

After looking into POE (which is lovely and clever), I've decided to use SocketFactory for my tcp server needs. This is great until I get into some error handling. I usually set alarms, which do some clean up, and then close the socket. I close the socket to get the connection to drop, thus allowing the client to drop off.

Normally, I just use close(). But I need the socket name for that, and I have no idea how to find the socket that I'm using inside a session.

I tried using getsockname with no success. Any monks out there know either how to close a particular socket, or where the HEAP keys are documented?

Here's a sample of what I'm trying to do. Also, my clients don't have access to ALARM (Winders), so the drop has to happen on my end.

#!/usr/bin/perl use POE qw( Wheel::SocketFactory Wheel::ReadWrite Filter::Line Driver::SysRW ); new POE::Session ( _start => \&collector, agent_handler=>\&agent_handler, accept_failed=>\&accept_failed, agent_input=>\&agent_input, agent_error=>\&agent_error ); $poe_kernel->run(); exit; # Session Sub Defs sub collector { $_[HEAP]->{listener} = new POE::Wheel::SocketFactory ( BindPort => PORT, Reuse => 'yes', SuccessEvent => 'agent_handler', FailureEvent => 'accept_failed' ); print "SERVER: Started Collector on port ",PORT,"\n"; } # Non-Session Sub Defs sub accept_failed { my ($function, $error) = @_[ARG0, ARG2]; delete $_[HEAP]->{listener}; print "SERVER: call to $function() failed: $error.\n"; } sub agent_handler { print "Agent handler called\n"; my ($heap, $socket) = @_[HEAP, ARG0]; $heap->{readwrite} = new POE::Wheel::ReadWrite ( Handle => $socket, Driver => new POE::Driver::SysRW (), Filter => new POE::Filter::Line (), InputEvent => agent_input, ErrorEvent => agent_error, ); $heap->{peerhost} = inet_ntoa($_[ARG1]); print "CHILD: Connected to $heap->{peerhost}.\n"; } sub agent_input { $heap=$_[HEAP]; print "agent_input called\n"; $input_sysid=$_[ARG0]; print "input system id is $input_sysid from $heap->{peerhost}\n"; print "Sending ack back\n"; $heap->{readwrite}->put( "Hello, client!" ); $agent_alarm = $poe_kernel->delay_set( agent_error, 5 ); } sub agent_error { print "Got an agent error, exiting agent session!\n"; my ($function, $error) = @_[ARG0, ARG2]; print "SERVER: call to $function() failed: $error.\n"; # I sure would like to close the socket here... }


Replies are listed 'Best First'.
Re: How do I close a POE SocketFactory Socket?
by rcaputo (Chaplain) on Jun 24, 2002 at 23:09 UTC

    Wheels are meant to manage the things they're working with. Usually those are filehandles, as in the cases of SocketFactory, ListenAccept, FollowTail, ReadWrite, and Run. Normally you needn't hold copies of the handles themselves, but it can be handy when you want a handle to persist beyond the lifetime of its wheel.

    Anyway, closing handles is very easy: Just delete all copies of the wheels that wraps them. When wheels are DESTROYed, the handles embedded within them usually are too.

    sub agent_error { print "Got an agent error, exiting agent session!\n"; my ($function, $error) = @_[ARG0, ARG2]; print "SERVER: call to $function() failed: $error.\n"; # I sure would like to close the socket here... delete $_[HEAP]->{readwrite}; }

    -- Rocco Caputo / /

      Ah, I see. It leaves me with one question, tho.

      This server will handle many connections at the same time. Let's say that 10 of them are online currently. If one of them gets alarmed and calls destroy on the readwrite wheel, what happens to the other nine?

      Will they go on their merry way? I'm used to working with forked children, which contain their own copies of things that can be smacked at will.

      How do these work?

      Many thanks for the insight so far...


        First I'd like to mention that you can have multiple alarms in POE, even in Windows. See POE::Kernel's documentation on the alarm() and delay() functions.

        The server as it's written will create one ReadWrite wheel per client connection, and they're all stored in the same place: $heap->{readwrite}. In other words, each new connection will clobber the last. That's probably not what you want to do. :)

        There are a few ways around this. First, each new ReadWrite wheel can be stored in a different $heap element. This stores each new wheel under its unique ID.

        my $wheel = POE::Wheel::ReadWrite->new( ... ); $heap->{readwrite}->{$wheel->ID} = $wheel;

        Every wheel event comes with a copy of the wheel's ID so you can tell which connection caused some activity. You might write your error handler like this:

        sub agent_error { my ($heap, $function, $error, $wheel_id) = @_[HEAP, ARG0, ARG2, ARG3 +]; print "SERVER: call to $function() failed: $error.\n"; print "Disconnecting agent!\n"; # Close the socket here... delete $heap->{readwrite}->{$wheel_id}; }

        Another way is to create a new Session instance for each client connection. This way is closest to fork() without really using fork: each connection has its own $heap to store things in.

        If you're in the mood for a very high level approach, see the documentation for POE::Component::Server::TCP. You can find a very short Server::TCP example in this section of POE's cookbook.

        -- Rocco Caputo / /

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://176971]
Approved by Ovid
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (10)
As of 2018-07-23 15:58 GMT
Find Nodes?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?

    Results (472 votes). Check out past polls.