Here is some code that exhibits the hanging socket problem.  It's three
scripts: a server and 2 clients, one that works (XML::Lite based) and one
that hangs (POE based).  The POE client/server represents the client and
server side of a larger server process, which is serving as a XML RPC broker
of sorts (a few incoming requests initiating many outgoing requests, with
aggregation of results.)

The fact that rpcclient.pl hangs and rpcclient2.pl does not may come down to
whether the client socket code closes the socket or expects the server to
close it first.  The PoCoCl::HTTP code clearly expects the server to close
the connection; it ain't happening. If there's an opportunity to shut down
the socket once the POE::Component::RPCXML::Server->send_resp() I/O is
finished, perhaps that's the answer.  I have a feeling it will be obvious to
someone...

Suggestions welcome.  Thanks for any help!

Alan



rpctestserver.pl:

#!/usr/bin/perl -w

# a "minimal" server that replicates the structure of an XML RPC
# server session of a larger project.  A dispatcher session creates
# a session to handle each request.  Not shown is all the machinery
# for registering methods from other sessions, error legs, etc.
#
# rpctestclient.pl implements the client side

use strict;

use POE;

# where to listen
my $addr = '127.0.0.1';
my $port = '8888';

# the XML RPC dispatcher session - one created to listen for requests
POE::Session->create(
  inline_states => {
      _start   => sub {
        print "listening on $addr:$port...\n";
        $_[KERNEL]->alias_set('dispatcher');
        $_[HEAP]->{listener} = POE::Wheel::SocketFactory->new(
          BindAddress    => $addr,
          BindPort       => $port,
          Reuse          => 'yes',
          SuccessEvent   => 'conn_success',
          FailureEvent   => 'conn_failure',
        );
      },
      conn_success => sub {
        print "got connection\n";
        Request->new( $_[ARG0] );
      },
      conn_failure => sub {
        print "failure\n";
        delete $_[HEAP]->{listener};
      },
    },
  );

$poe_kernel->run();
exit(0);

package Request;

# a per-request session object

use strict;

use POE qw(
    Component::RPCXML::Server
);
use RPC::XML ();
use RPC::XML::Parser ();

# create a session to handle each request
sub new {
  my $handle = $_[1];
  POE::Session->create(
    inline_states => {
      _start => sub {
       $_[HEAP]->{wheel} = POE::Wheel::ReadWrite->new(
            Handle        => $handle,
            Filter        => POE::Filter::HTTPD->new(),
            InputEvent    => 'request',
            ErrorEvent    => 'http_error',
       );
     },
     request => sub {
       my $xr = RPC::XML::Parser->new()->parse( $_[ARG0]->content );
       print "responding to ",$xr->name,"\n";
       # just return a generic hash response
       POE::Component::RPCXML::Server->send_resp(
           $_[HEAP]->{wheel},
           RPC::XML::response->new( { status => 'ok' } )->as_string,
       );
     },
     http_error => sub {
       print "http_error - closing wheel\n";
       delete $_[HEAP]->{wheel};
     },
    },
  );
}

1;

rpctestclient1.pl:

#!/usr/bin/perl -w

# a "minimal" client that replicates pieces of a larger project that
# employs XML RPC for incoming and outgoing requests.  This code 
# sets up the client side and initiates a dummy request.
#
# rpctestserver.pl implements the server side.

use strict;
use POE;
use POE::Component::RPCXML::Client;
use RPC::XML;
use Data::Dumper;

# where rpctestserver.pl is waiting...
my $url = 'http://127.0.0.1:8888';

# a dummy request
my $req = RPC::XML::request->new('testmethod');

# the HTTP client session - one created to service many requests
# Note: enable DEBUG and DEBUG_DATA in POE::Component::Client::HTTP to
# see where the client hangs.
POE::Component::Client::HTTP->spawn( Alias => 'httpclient' );

# the XML RPC client session - one created to service many requests
POE::Session->create(
  inline_states => {
      _start   => sub {
        $_[KERNEL]->alias_set('rpcxml');
      },
      call     => sub {
        $_[HEAP]->{callback} = $_[SENDER]->postback($_[ARG1]);
        my $r = HTTP::Request->new( POST => $_[ARG2] );
        $r->content( $_[ARG0]->as_string );
        $r->push_header( 'Content-Type', 'text/xml' );
        $r->push_header( 'Content-Length', length $r->content );
        $_[KERNEL]->post( httpclient => request => response => $r );
      },
      response => sub {
        $_[HEAP]->{callback}->(
            RPC::XML::Parser->new()->parse($_[ARG1]->[0]->content)
        );
      },
    },
  );

# initiate a client request - singleton to initiate one request and exit
POE::Session->create(
  inline_states => {
    _start => sub {
       $_[KERNEL]->post( rpcxml => call => $req => response => $url );
    },
    response => sub {
       print Dumper([EMAIL PROTECTED]);
       exit(0);
    },
  },
);

$poe_kernel->run();

rpctestclient2.pl:

#!/usr/bin/perl -w

# XMLRPC::Lite version of the client, to initiate a dummy request to the
# rpctestserver.  This one does not hang.

use strict;

use XMLRPC::Lite;
use Data::Dumper;

my $url = 'http://127.0.0.1:8888';

print 'result = ', Dumper(
    XMLRPC::Lite -> proxy($url) -> testmethod -> result
  );

Reply via email to