#!/usr/bin/perl -w -T
use strict;
use CGI::Carp qw(fatalsToBrowser);
use POSIX;
print "Content-type: text/html\n\n";
Die CGI-Spec verlangt hier CR + LF statt "\n". Die CGI-Library würde sich darum automatisch kümmern ...
$ENV{'PATH'}='/bin:/usr/bin';
perlsec sagt, dass noch mehr Environment-Variablen ausgemistet werden sollten.
print qq~
<HTML>
<HEAD><TITLE>Test</TITLE></HEAD>
<BODY>
<tt>~;
Auch das würde die CGI-Library erledigen.
my @returnvalue=();
$|=1;
pipe READFD,WRITEFD;
my $oh= select(WRITEFD); select($oh);
Was genau soll diese Zeile (^^^) bewirken?
my $Kind_pid = fork();
die "Aua: $!\n" unless defined $Kind_pid;
if($Kind_pid) {
use POSIX ":sys_wait_h";
Wenn Du das so schreibst, erwartest Du vermutlich, dass die POSIX-Libraray nur im Parent geladen wird. Das passiert aber nicht. Siehe perlfunc.
my $waitcount=1;
do {
my $Kind_pid = waitpid(-1,&WNOHANG);
#Wartenachricht hier/bin/ps aux;
print "...".$waitcount;
$waitcount++;
sleep 2;
} until $Kind_pid == -1;
close(WRITEFD);
@returnvalue=<READFD>;
}
else {
my $cvs='';
sleep 10;
my @cvscan=/bin/echo "foobar";
close(READFD);
foreach $cvs (@cvscan){
#print $cvs."<br>\n";
print WRITEFD $cvs;
}
close STDOUT;
exit(0);
}#Weitere Verarbeitung hier
print "\nAusgabe hier\n";
print @returnvalue;
print qq~
</tt>
</BODY>
</HTML>~;Aufruf an der Kommandozeile:
perl -T test.pl
Es sollte perl -T -w test.pl sein.
Content-type: text/html
<HTML>
<HEAD><TITLE>Test</TITLE></HEAD>
<BODY>
<tt>...1...2...3...4...5...6...7...8...9...10...11...12...13...14
(Ctrl-C), denn es terminiert wieder nicht :-(Dann Dein Vorschlag bzgl. ps aux:
geänderter Abschnitt:
if($Kind_pid) {
use POSIX ":sys_wait_h";my $waitcount=1;
do {
my $Kind_pid = waitpid(-1,&WNOHANG);
#Wartenachricht hier/bin/ps aux;print "...".$waitcount;
$waitcount++;
sleep 2;
} until $Kind_pid == -1;
close(WRITEFD);
@returnvalue=<READFD>;
}perl -T test.pl
Content-type: text/html<HTML>
<HEAD><TITLE>Test</TITLE></HEAD>
<BODY>
<tt>
[viel Output gekürzt]
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
[...]
root 3561 6.6 0.7 6796 3076 /UNIONFS/dev/pts/0 S+ 08:23 0:00 perl -T test.pl
/UNIONFS? Was ist das für eine Testumgebung? Knoppix?
root 3563 0.0 0.7 6504 2856 /UNIONFS/dev/pts/0 S+ 08:23 0:00 perl -T test.pl
root 3570 0.0 0.2 4268 944 /UNIONFS/dev/pts/0 R+ 08:23 0:00 /bin/ps aux
Wo ist /bin/echo ?
Warum läuft das Perl-Script als root und nicht als wwwrun (oder wie auch immer der Webserver-Account heißen mag)?
Der zweite Teil beendet sich, aber die Warteschleife bekommt's nicht mit.
So, jetzt warte ich auf Erleuchtung, großer Meister.
pipe rauswerfen, Safe Pipe Opens aus perlipc benutzen. Im Kindprozess kein großartiges Theater veranstalte (zweiter fork durch ``, Ausgabe nochmals puffern), sondern schlicht und ergreifend "exec $prog,@args; die 'exec failed';". Nicht mehr.
Wenn Webserver bzw. Browser wirklich in ein Timeout hineinlaufen, das aufgerufene Programm beschleunigen, z.B. indem Du es etappenweise mit jeweils weniger Daten fütterst oder den Algorithmus gründlich optimierst.
Ein anderer Plan wäre, mit dem ersten Aufruf das lang laufende Programm vollständig im Hintergrund zu starten (siehe "Complete Dissociation of Child from Parent" in perlipc), alle Ausgaben in eine Datei umzuleiten und dann per CGI und HTTP refresh darauf warten, dass das langsame Programm terminiert. Letzteres sicher und zuverlässig zu erkennen ist nicht ganz trivial, am sichersten dürfte wohl eine Signaldatei sein, die mit Ende des langsamen Programms gelöscht oder angelegt wird. Ein einfaches Shell-Script könnte das als Wrapper erledigen, dabei dient die Ausgabedatei selbst als Marker:
#!/bin/bash
PATH=/bin:/usr/bin
rm -f output.txt
schnecke "$@" > output.tmp 2> errors.txt < /dev/null
mv output.tmp output.txt
Sobald output.txt existiert, ist "schnecke" fertig, und die 100. Instanz des CGIs kann output.txt und error.txt auswerten statt den Nutzer wieder um 10 Sekunden zu vertrösten.
Alexander