Thread Tipp: FastCGI mit FCGI oder CGI::Fast als externer Server (2 answers)
Opened by pq at 2012-08-03 21:57

pq
 2012-08-03 21:57
#160610 #160610
User since
2003-08-04
12207 articles
Admin1
[Homepage]
user image
Nachdem ich sehr lange gebraucht habe, um FastCGI zum laufen zu bringen, da ich über mehrere dokumentations-bugs gestolpert bin, möchte ich hier das ganze als beispiel beschreiben.

Apache-Config:
Code: (dl )
1
2
FastCgiExternalServer /tmp/myapp.fcgi -host localhost:8888
Alias /myapp /tmp/myapp.fcgi/


Ganz wichtig ist hier:
Den Daemon startet man selbst von Hand. /tmp/myapp.fcgi ist hier nur ein virtueller Pfad, der nicht existieren sollte.

Das Alias mappt dann /myapp auf den externen Server auf port 8888.

Alternativ kann man auch einen Socketpfad angeben.

Als nächstes versuchte ich, das Skript als Daemon zu starten. Hier meine fehlgeschlagenen Versuche:
more (13.6kb):

Zuerst CPAN:CGI::Fast. Aus der Doku:

Code (perl): (dl )
1
2
3
4
5
6
7
use CGI::Fast;
&do_some_initialization();
$ENV{FCGI_SOCKET_PATH} = "sputnik:8888";
$ENV{FCGI_LISTEN_QUEUE} = 100;
while ($q = new CGI::Fast) {
    &process_request($q);
}


Das probierte ich aus, jedoch wurde beim Start des Skripts gleich ein Request durchlaufen und danach war das Skript zu ende.

Also probierte ich stattdessen direkt CPAN:FCGI.

Dokmentation:

man findet dort direkt kein Beispiel, aber einen Hinweis auf das im Paket enthaltende remote.pl. Das skript sieht dann so aus:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
use FCGI;
my $socket = FCGI::OpenSocket( ":8888", 5 );
my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR,
    \%ENV, $socket );

my $count;
while( $request->Accept() >= 0 ) {
    print "Content-type: text/html\r\n\r\n";
    print ++$count;
}
 
FCGI::CloseSocket( $socket );


Das lief auch erstmal.

Jetzt brauchte ich natürlich ein CGI-Objekt. Also:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
use FCGI;
my $socket = FCGI::OpenSocket( ":8888", 5 );
my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR,
    \%ENV, $socket );

while( $request->Accept() >= 0 ) {
    my $cgi = CGI->new;
    my $test = $cgi->param('test');
    print "Content-type: text/html\r\n\r\n";
    print "test: $test";
}
 
FCGI::CloseSocket( $socket );


Jetzt bemerkte ich, dass $test, wenn einmal gesetzt, nie mehr verschwand. Das CGI-Objekt holte sich also die Daten nicht neu aus dem Request.

Die Lösung fand ich über eine Suchmachine.
Vor dem CGI->new muss man ein CGI::initialize_globals(); aufrufen.
Das hat dann funktioniert. Sollte in der Doku hinzugefügt werden.

Jetzt wollte ich noch wissen, warum es mit CGI::Fast nicht ging.

Auch hier half mir der Eintrag bei stackoverflow, den ich gefunden hatte:
http://stackoverflow.com/questions/7206323/perl-we...

Dort ist ein RT-Ticket verlinkt:
https://rt.cpan.org/Ticket/Display.html?id=70609

Die Lösung: Die Initialisierungen der Umgebungsvariablen müssen *vor* dem laden der Module passieren.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
use CGI::Fast;
BEGIN {
    $ENV{FCGI_SOCKET_PATH} = "sputnik:8888";
    $ENV{FCGI_LISTEN_QUEUE} = 100;
}
&do_some_initialization();
while ($q = new CGI::Fast) {
    &process_request($q);
}


und die richtig lautenden Beispiele:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
BEGIN {
    $ENV{FCGI_SOCKET_PATH} = "localhost:8888";
    $ENV{FCGI_LISTEN_QUEUE} = 100;
}
use CGI::Fast;
...
my $count;
while (my $cgi = new CGI::Fast) {
    ...
}


Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
use FCGI;
my $socket = FCGI::OpenSocket( ":8888", 5 );
my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket );

my $count;
while( $request->Accept() >= 0 ) {
    CGI::initialize_globals();
    my $cgi = CGI->new;
    ...
}
 
FCGI::CloseSocket( $socket );


Dieses Skript dann einfach starten und der Daemon läuft.
Last edited: 2012-08-03 22:04:12 +0200 (CEST)
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem

View full thread Tipp: FastCGI mit FCGI oder CGI::Fast als externer Server