tcp_server hang

Eduard Ivanov houspi at gmail.com
Tue Sep 18 10:23:19 CEST 2018


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.schmorp.de/pipermail/anyevent/attachments/20180918/47ff28b5/attachment.html>


More information about the anyevent mailing list