Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Multi-process Win32 HTTP Daemon

by rfoskett (Initiate)
on Apr 29, 2006 at 23:58 UTC ( [id://546534]=perlquestion: print w/replies, xml ) Need Help??

rfoskett has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I'm trying to get a multiprocess win32 http daemon working however seem to be having problems in getting the response back from the server.

The eventual aim of this is to have a prespawning SOAP server that can expose OLE APIs to nonwindows platforms. I dont want to use the obvious choice of fork as activeperl currently creates threads behind the scene and so want to avoid any potential threadsafe issues with the OLE classes.

Anyway, ive adapted the below code from this old article

http://www.webtechniques.com/archives/2000/03/junk/

When starting the daemon, then running individual client requests - the inherited Win32 process correctly gets the request send by the client however is not able to send back the response.

Any thoughts on how to fix this (or ideas on a better approach) would be appreciated.

Thanks

Roger

daemon.pl

use strict; use warnings; use HTTP::Daemon; use HTTP::Status; use HTTP::Response; use HTTP::Headers; use Win32::Process; my $listener = HTTP::Daemon->new( LocalAddr => '127.0.0.1', LocalPort => 2112, Listen => 5) || die ("Listener could not be created\n"); my $counter = 0; print "$$] Listener waiting for Requests on ".$listener->url."\n"; # This loop monitors the port for connections for(;my $c = $listener->accept; $c->close) { print "\n$counter] Accepted Connection\n"; binmode $c; spawn($c); } sub spawn { my $c = shift; # Make a backup of STDOUT and STDIN #open( STDOUT_BACKUP, ">&STDOUT" ); open( STDIN_BACKUP, "<&STDIN" ); # redirect my $socket_no = $c->fileno; open(STDIN, "<&$socket_no") || die $!; #open(STDOUT, ">&") || die $!; # where to ? $c->close; # Spawn process my $obj; Win32::Process::Create($obj, $^X, "$^X serverx.pl", 1, NORMAL_PRIORITY_CLASS, '.') || die "ERROR: failed to execute: $^X serverx.pl; ". Win32::FormatMessage(Win32::GetLastError()); # Redirect STDOUT to what it used to be... #open( STDOUT, ">&STDOUT_BACKUP" ); open( STDIN, "<&STDIN_BACKUP" ); # Close the backup of STDOUT #close( STDOUT_BACKUP ); close( STDIN_BACKUP ); print "spawned ".$obj->GetProcessID."\n"; }
serverx.pl
use strict; use warnings; use Cwd; use lib getcwd; use HTTP::Daemon; use SDaemon; use HTTP::Status; use IO::Select; use Data::Dumper; # Create a client connection object "the hard way" my $c = HTTP::Daemon::ClientConn->new_from_fd ('STDIN', "+>"); # backfill the necessary client connection attributes ${*$c}{'httpd_daemon'} = SDaemon->new(); binmode $c; $c->autoflush(1); close STDIN; my $i = 0; while (my $req = $c->get_request()) { print STDERR "$$] $i Request\n".$req->as_string."\n"; my $content = "<HTML><B>Pid: $$</B> ".(scalar localtime())."</HTML>"; my $hdrs = HTTP::Headers->new(('Content-Length' => length($content))); my $res = HTTP::Response->new(RC_OK,'',$hdrs,$content); $c->send_response($res); print STDERR "$$] $i sent response\n"; } $c->close;
SDaemon.pm
package SDaemon; sub new { my ($classname, $port) = @_; my $self = {}; bless($self, $classname); $self->{PORT} = $port; return $self; } sub url { my $u = 'http://127.0.0.1:'.$self->{PORT}.'/'; return $u; } sub product_tokens { "libwww-perl-daemon/1.21"; } 1;
client.pl
use strict; use warnings; use LWP::UserAgent; my $ua = LWP::UserAgent->new; print "Sending request...\n"; my $res = $ua->post('http://127.0.0.1:2112', [ 'q' => 'blah', 'pg' => 'q', 'avkw' => 'tgz', 'kl' => 'XX', ] ); print "Got response\n"; if ($res->is_success) { print "Content: ".$res->as_string."\n"; } else { die "ERROR: ".$res->status_line; }

Replies are listed 'Best First'.
Re: Multi-process Win32 HTTP Daemon
by Errto (Vicar) on Apr 30, 2006 at 00:34 UTC
    I confess that my Win32 knowledge is not spectacular, so I assume that the file descriptors carry over properly in the way you expect them to. But I do have one question: perhaps I'm missing the obvious, but why is all the STDOUT redirection code commented out?
Re: Multi-process Win32 HTTP Daemon
by BrowserUk (Patriarch) on Apr 30, 2006 at 05:46 UTC

    Your code seems to work fine on my system (XP & AS811). What errors are you seeing?

    Server trace over 20+ 5 connections. (20 worked fine, but showed nothing extra)

    Client trace


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Unfortunately, the client response isnt correct in that it always reads the same regardless of response object formed on the server:
      Got response Content: HTTP/0.9 200 (OK) EOF Client-Date: Sun, 30 Apr 2006 05:50:47 GMT Client-Peer: 127.0.0.1:2112 Client-Response-Num: 1
      The client correctly prints the server pid & time when running through a normal HTTP::Daemon so think this is due to LWP::UserAgent/HTTP::Response on the client side.

        If you look back up at the client log I posted, you'll see that there are 3 different times produced amongst the 5 responses shown:

        Client-Date: Sun, 30 Apr 2006 05:50:44 GMT Client-Date: Sun, 30 Apr 2006 05:50:46 GMT Client-Date: Sun, 30 Apr 2006 05:50:47 GMT

        And if I run more client I get more different times. They are not all unique because 1 second is a long time in computer terms. It just means that the server was able to respond to 2 or more client connects within the same second. For a real server you would want to achieve a much higher rate than 1 per second.

        As far as I can tell from your code, all the other data are invarient. You could use Time::HiRes to get finer granularity to convince yourself, or perhaps add another header with a unique value.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Multi-process Win32 HTTP Daemon
by BrowserUk (Patriarch) on Apr 30, 2006 at 18:55 UTC

    Hint: The code you posted could *never* work.

    # Create a client connection object "the hard way" my $c = HTTP::Daemon::ClientConn->new_from_fd( 'STDIN', "+>" );

    'STDIN' is just a string no different from 'this' or 'That! or 'Hello world!'.

    In particular, it is not the same as the bareword STDIN, which is a pre-opened filehandle, and the what is used in the original code that you downloaded:

    # Create a client connection object "the hard way" $c = HTTP::Daemon::ClientConn->new_from_fd(STDIN, "+>");

    However, that code doesn't make any sense either, as fdopen take an integer parameter not a filehandle glob, so I do not see how that would ever have worked.

    If you change that line to

    my $c = HTTP::Daemon::ClientConn->new_from_fd( fileno( STDIN ), '+>' ) +;

    The code will work.

    c:\test\546536>client Sending request... Got response Content: HTTP/1.1 200 OK <<<<<<<<<<<<<<<<<<<<< **** Note: No EOF *** +** Client-Date: Sun, 30 Apr 2006 18:44:08 GMT Client-Peer: 127.0.0.1:2112 Client-Response-Num: 1 Date: Sun, 30 Apr 2006 18:44:08 GMT Server: libwww-perl-daemon/1.21 **** The content I assume you were expecting, but didn't mention even +when queried. ***** Content-Length: 56 X-Content:: <HTML><B>Pid: 1572</B> Sun Apr 30 19:44:08 2006</HTML> <HTML><B>Pid: 1572</B> Sun Apr 30 19:44:08 2006</HTML>

    Free advice:

    1. If you download code from random sources and it doesn't compile with use strict, be suspicious.
    2. If you make changes to make it use strict complient, best to mention these when you post the modified code.
    3. If you do not understand enough about the code you've downloaded to recognise that the output you are receiving is a big fat clue:
      Got response Content: HTTP/0.9 200 (OK) EOF <<<<<< ******* EOF means End of file ** +*** Client-Date: Sun, 30 Apr 2006 05:50:47 GMT Client-Peer: 127.0.0.1:2112 Client-Response-Num: 1

      And that the times being displayed are clearly labelled Client-time:

    4. If you cannot describe what is wrong with the output you are receiving

    It's a pretty low trick to just throw the code onto a message board and expect others to sort out your problem.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Perfect it works, however as you mentioned the code would have never worked - hence the reason for posted in the first place.
      Thanks for your help
Re: Multi-process Win32 HTTP Daemon
by shonorio (Hermit) on Apr 30, 2006 at 15:38 UTC
    What you want's looks much more complex that you are showing, because this maybe you should look at POE framework for creating event-driven multitasking programs in Perl and your POE Cookbook, where you can see a examples about how to create one Web server.

    Using POE has 2 good things, first is easy and second is multi-plataform. To build your server running as server on Win32 you can use POE::Component::Daemon::Win32.

    If you are looking just for SOAP, take a look of SOAP::Lite.

    Using one of these frameworks, your system will be easier to write and support. Think about this.

    Solli Moreira Honorio
    Sao Paulo - Brazil

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://546534]
Approved by Errto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (8)
As of 2024-04-25 10:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found