perlunity.de - PERL | JAVASCRIPT | PHP | MySQL | APACHE



#!/COMMUNITY

Members: 5374
davon online: 1
weitere User: 19
Click for quality!




11.02.2012 / 23:15

Community-Member werden   |   Paßwort vergessen   |   OnlineMonitor (1) Wer ist online ... OnlineMonitor starten !
     

 

Home


PERLscripts


PHPscripts


JAVAscripts


Hilfreiches


Links2www


Newscenter


Community


Interna




Community  »  Web-Entwicklung sonstiges zur Themenübersicht Themensuche Themenansicht in Thread-Modus


BeitragWeb-Server in Perl
Seitenanfang
Hallo zusammen,

ich möchte einen Web-Server in Perl realisieren.
Habe mittlerweile auch schon verschiedene Ansätze mit Erfolg ausprobiert.

Meine bisher ungelösten Probleme:
1. Wie kann ich die Bandbreite reduzieren, z.B. auf 10kByte/s, da ich den Server zu Hause per DynDns laufen lassen möchte, ich eine maximale Upload-Gescwindigkeit von ca. 20kByte/s habe und das (übrige Inter-)Netz bei Anfragen an den Server nicht lahmlegen möchte.
2. Wie kann ich erreichen, dass der Server mehrere Client-Verbindungen "gleichzeitig" bearbeitet.
Alle meine bisherigen Versuche (Select, Fork, Thread) laufen darauf hinaus, dass der Server die laufende Anfrage eines Client beantwortet und die Anfragen der anderen Clients in einer Warteschlange lässt. Er soll aber alle Anfragen
parallel und "gleichzeitig" in kleinen Häppchen mit vielleicht einem oder einigen kByte liefern.
Stellt euch vor, Ihr fragt einen Download mit sagen wir mal 1MByte an dem Server an, dann dauert dieser Download bei 10k/s ca. 100s.
Wenn jetzt ein anderer auf eine normale Webseite des Server mit vieleicht 5kByte zugreift, muss er eben bis zu 100s warten, er soll sie aber sofort (nach 1 bis einigen Sekunden) erhalten.

Ich hab schon überlegt die TCP-Abwicklung selber z.B. mit RAW Sockets zu machen, aber bisher nicht im Entferntesten was gefunden, was mir weiterhelfen könnte.

Das Problem scheint darin zu bestehen, dass der Socket für andere Anfragen solange blockiert bleibt, bis die aktuelle Verbindung geschlossen wird (close), was ich aber erst machen kann, wenn die Daten komplett geschrieben wurden.

Zu der ersten Frage habe ich schon Ideen, dass ich die Ausgaben in einer Liste, Array speichere und dann sekündlich häppchenweise raussende, sind z.B. 5 parallele Anfragen, mache ich die Häppchen z.B. 2k (10k/5) gross.

Aber vieleicht gibt es in Verbindung mit der Lösung des 2.Problems elegantere Lösungen.

Vielen Dank und Gruss
Dieter

Datum: 13.01.2009-12:37

Beitragre: Web-Server in Perl
Seitenanfang
üblicherweise löst man das so, dass man einen parent-Prozess hat, der eingehende Verbindungen entgegennimmt und dann jeweils einen child-Prozess fork()t, der dann die Verbindung übernimmt.

Der parent-Prozess ist also fast sofort wieder "zurück", um sich um weitere eingehende Requests zu kümmern.

Im PerlCookbook ist dazu einiges zu lesen. Auch zu solchen Server-Konstrukten, die einen Pool von pre-forked children benutzen, das geht dann ncoh schneller.

Gruss, Sven

PS: Es gibt bereits verschiedenste Implemetierungen von Webservern mit Perl (siehe cpan) - warum willst Du einen Neuen schreiben? Challenge?

Datum: 13.01.2009-14:48

Beitragre: Web-Server in Perl
Seitenanfang
Vielen Dank für die Antwort.
Ich versuch einfach aus Spass an der Freude einen
Webserver zu schreiben. Ich habe auch bereits schon einen ziemlich weit gebracht, sprich mit Perl,PHP und sogar C-Script-Interface.
In diesem Webserver verwende ich select mit can_read(). Allerdings bin ich dann, als ich versucht habe Ihn in der Bandbreite zu begrenzen auf das geschilderte Problem gestossen.
Auch Versuche mit Fork oder Treads haben das Problem nicht gelöst.

Damit eine sinnvolle Diskussionbasis entsteht
folgt ein Perl-Source, der das Problem aufzeigt.


#!/usr/bin/perl -w

# TCP/HTTP-Server
# (c) 2009 Dieter Heinrich

use strict;
use warnings;

use Socket;
use IO::Socket::INET;
use IO::Select;

select(STDERR); $|=1; select(STDOUT); $|=1; # Autoflush

#=================================================================================
my $socket = IO::Socket::INET->new
( LocalPort=> 80,
LocalAddr=> "0.0.0.0",
Listen => 5,
ReuseAddr=> 1,
Proto => "tcp",
Type => SOCK_STREAM
);

#=================================================================================
my @fhn=(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); # Client-Handles
my @fhp=(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); # Lese-Zeiger auf $fhb[$i]
my @fhb=("","","","","","","","","","","","","","","",""); # Ausgabe-Puffer

my $sel = new IO::Select($socket); # Selectobjekt für diesen Socket erstellen

#=================================================================================
while(1)
{ my (@rdy,$buf);
@rdy=$sel->can_read(1); # Client-Anfragen ?, 1s blockierend

# Ausgabe im Sekundentakt häppchenweise (256Byte) senden
# eine Schleife mit $sel->can_write(0) ist offensichtlich nicht erforderlich
for (my $i=0; $i<=$#fhn; $i++) # offene Ausgabe-Anforderungen
{ if ($fhn[$i])
{ $fhp[$i]+=syswrite($fhn[$i],$fhb[$i],256,$fhp[$i]);
$fhn[$i]->flush; # Ausgabe flush (wahrscheinlich unnötig)
if ($fhp[$i]>=length($fhb[$i])) # alles ausgegeben ?
{ $sel->remove($fhn[$i]);
$fhn[$i]->close; # Verbindung schliessen
$fhn[$i]=0; # Verbindung = 0
}
}
}

# Client-Anfragen entgegennehmen
foreach my $fh (@rdy) # Client-Anfragen bearbeiten
{ my ($methode,$doc,$protokol)=("","","");
if ($fh==$socket)
{ $sel->add($socket->accept);
print "Client angenommen:";
} else
{ binmode($fh); $fh->autoflush(1);
RDL: while ($buf=<$fh>)
{ if ($buf=~/^(GET|POST)/) # Client-Anforderung ?
{ ($methode,$doc,$protokol)=split(/ /,$buf,3);
} elsif ($methode)
{ $buf =~s/[\x0a\x0d]+$//; # CR am Ende weg
if ($buf eq "") # Leer-Zeile ?
{ print $fh "HTTP/1.0 200 OK\n";
print $fh "Server: Test 1.0\n";
print $fh "Content-Type: text/html\n";
print $fh "Connection: close\n\n";
$doc =~ s/^\///g; # '/' am Anfang weg

# die Datei wird nicht sofort ausgeliefert, sondern in einen Ausgabe-Puffer
# geschrieben, der anschliessend zu Anfang der while-Schleife häppchen-weise
# im Sekunden-Intervall (can_read(1)) ausgegeben wird
my $i=0; # freien Ausgabe-Kanal suchen
while ($i<=$#fhn) { if (!$fhn[$i]) { last; } $i++; }
print $i."\n";
if ($i<=$#fhn)
{ $fhp[$i]=0; # Lese-Zeiger = 0
$fhb[$i]=""; # Ausgabe-Puffer leeren
$fhn[$i]=$fh; # Client-Handle, Ausgabe-Puffer gültig
open DOC,"<",$doc; # Ausgabe-Puffer füllen
while (<DOC>) { $fhb[$i].=$_; } close DOC;
}
last RDL;
}
}
}
#$sel->remove($fh); # hier würde die Client-Verbindung
#$fh->close; # normalerweise wieder geschlossen
}
}
}

# Verhalten:
# fordert ein Client ein Dokument an, wird dies häppchenweise im Sekundentakt ausgeliefert.
# Dabei wird der Kanal @fhn mit dem Index 0 genommen.
# fordert während dieser Ausgabe ein zweiter Client ein Dokument an, so wird dieser erst
# bedient, wenn der erste Client fertig bedient wurde. Für den zweiten Client wird wieder
# der Kanal @fhn mit dem Index 0 genommen.

1;
__END__

Gruss Dieter

Datum: 13.01.2009-19:28

-






-
-