tcp_server hang
Mons Anderson
mons at cpan.org
Wed Sep 19 04:27:12 CEST 2018
It’s kinda bad http server. No checks for result of syswrite, no use
of AnyEvent::Handle for this.
Take a look at the source of AnyEvent::HTTP, AnyEvent::HTTPD or
AnyEvent::HTTP::Server (only on github)
On Wed, Sep 19, 2018 at 2:05 AM Eduard Ivanov <houspi at gmail.com> wrote:
>
> Hello,
>
> Can someone help me with my problem?
> I'm writing a simple http server with anyEvent tcp_server.
> And my script hangs after processing 1018 requests.
> I tested it with ab.
>
> #!/usr/bin/perl -w
> #
> # Simple HTTP server with anyEvent
> #
>
> use strict;
> use POSIX;
> use Getopt::Std;
> use Socket;
> use IO::Socket;
> use AnyEvent;
> use AnyEvent::Socket qw/tcp_server/;
> use AnyEvent::Handle;
>
> use constant DEFAULT_PORT => 1080;
>
> my $DIRECTORY_ROOT = "/home/test/simple-http-server";
>
> my %commands = (
> "GET" => \&command_get,
> );
>
> my %status = (
> "200" => "OK",
> "404" => "NOT FOUND",
> );
>
> # Parsing command line options
> my %opts;
> getopts('hdl:p:', \%opts);
>
> if ($opts{'h'}) {
> Usage();
> exit(0);
> }
>
> my $log_level = 0;
> if ( exists($opts{'l'}) ) {
> $log_level = $opts{'l'};
> $log_level =~ s/\D//g;
> }
> $log_level = 1 if ($log_level !~ /\d/);
>
> my $port;
> if ($opts{'p'}) {
> $port = $opts{'p'};
> $port =~ s/\D//g;
> }
> $port = DEFAULT_PORT if (!$port);
>
> if ($opts{'d'}) {
> #Turn off log if run as a daemon
> $log_level = 0;
> daemonize();
> }
>
> my $condvar = AnyEvent->condvar;
>
> my %input_data = ();
> my $clients_count = 0;
> my $requests_total = 0;
>
> # Concurrent requests 128 is hardcoded in the AnyEvent::Socket module
> print_log(1, "Start new server on $port.\nMax of concurrent requests 128\n");
> my $guard = tcp_server "0", $port,
> sub {
> my ($fh, $host, $port) = @_;
> print_log(1, "new connect $fh, $host, $port\n");
> $clients_count++;
> $requests_total++;
> print_log(2, "Active clients count: $clients_count\nTotal processed requests: $requests_total\n");
> my $hdl = AnyEvent::Handle->new(
> fh => $fh,
> on_error => sub {
> my ($hdl, $fatal, $msg) = @_;
> delete $input_data{"$host:$port"};
> shutdown($fh, 2);
> $hdl->destroy;
> $clients_count--;
> }
> );
> my $id = "$host:$port";
> my $reader;
> $reader = sub {
> if ($_[1]) {
> $input_data{$id} .= $_[1] . "\n";
> } else {
> process_client($fh, $host, $port);
> print_log(2, "close connection $fh, $host, $port\n");
> shutdown($fh, 1);
> delete $input_data{$id};
> $hdl->destroy;
> $clients_count--;
> }
> $hdl->push_read( line => $reader );
> };
> $hdl->push_read( line => $reader );
> },
> sub {
> };
>
> #main loop
> AnyEvent->condvar->recv;
>
> =item process_client
>
> =cut
> sub process_client {
> my ($client, $host, $port) = @_;
>
> my $id = "$host:$port";
> print_log(2, "$client $id\n");
>
> if ( exists($input_data{$id}) ) {
> my @request_headers = ();
> foreach ( split(/\n/, $input_data{$id}) ) {
> push @request_headers, $_;
> }
> foreach ( @request_headers ) {
> my ($command, $param) = split(/ /, $_);
> if (exists($commands{$command})) {
> $commands{$command}->($client, $param);
> }
> }
> }
> }
>
> =item command_get
>
> =cut
> sub command_get {
> my $client = shift;
> my $param = shift;
>
> my $content = "";
> $param =~ s/\.\.//g;
> my $status_code;
> my $file;
> my $file_name = $DIRECTORY_ROOT . $param;
> if ( -f $file_name && open($file, $file_name)) {
> $status_code = "200";
> {
> local $/ = undef;
> $content = <$file>;
> }
> close($file);
> } else {
> $status_code = "404";
> $content = "";
> }
> syswrite($client, "HTTP/1.0 " . $status_code . " " . $status{$status_code} . "\n" );
> syswrite($client, "Content-type: text/html\n");
> syswrite($client, "Content-lenght: " . length($content) . "\n\n");
> syswrite($client, $content);
> }
>
> =item print_log
> print log info
> =cut
> sub print_log {
> my $level = shift;
> print STDERR join(" ", @_) if ($level <= $log_level);
> }
>
> =item daemonize
> run program as a daemon
> =cut
> sub daemonize {
> setsid() or die "Can't call setsid: $!";
> my $pid = fork() // die "Can't call fork: $!";
> exit(0) if $pid;
>
> open (STDIN, "</dev/null");
> open (STDOUT, ">/dev/null");
> open (STDERR, ">&STDOUT");
> }
>
> =item Usage
> print help screen
> =cut
> sub Usage {
> print <<EOF
> Usage $0 [-h] | [-d] [-l LogLevel] [-p Port]
> -h display this help and exit
> -d run as a daemon
> -l set log level of the messages. 1 by default. 0 to turn off.
> -p listen on Port
>
> EOF
> }
>
>
>
> --
> Eduard Ivanov
> _______________________________________________
> anyevent mailing list
> anyevent at lists.schmorp.de
> http://lists.schmorp.de/mailman/listinfo/anyevent
--
Best wishes,
Vladimir V. Perepelitsa aka Mons Anderson
<inthrax at gmail.com>, <mons at cpan.org>
http://github.com/Mons
More information about the anyevent
mailing list