【问题标题】:Perl HTTP serverPerl HTTP 服务器
【发布时间】:2013-01-20 13:59:30
【问题描述】:

我是 Perl 的新手,我有一个关于 HTTP 服务器和客户端 API 的问题。

我想编写一个接受来自 HTTP 客户端的请求的 HTTP 服务器。问题是我不知道该怎么做,因为我是一名 Java 开发人员,这对我来说有点困难。请你给我一些关于 Perl 的HTTP::Daemon 模块的教程和示例?

【问题讨论】:

    标签: perl


    【解决方案1】:

    我花了很多时间试图让许多用户同时创建一个“简单”可用的 Web 服务器。 HTTP::Daemon 和其他在线资源的文档对我没有帮助。

    这是一个工作(Ubuntu 12.10 和默认 Perl 包 v5.14.2)示例 preforked 具有不同内容类型页面和错误页面的 Web 服务器:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use CGI qw/ :standard /;
    use Data::Dumper;
    use HTTP::Daemon;
    use HTTP::Response;
    use HTTP::Status;
    use POSIX qw/ WNOHANG /;
    
    use constant HOSTNAME => qx{hostname};
    
    my %O = (
        'listen-host' => '127.0.0.1',
        'listen-port' => 8080,
        'listen-clients' => 30,
        'listen-max-req-per-child' => 100,
    );
    
    my $d = HTTP::Daemon->new(
        LocalAddr => $O{'listen-host'},
        LocalPort => $O{'listen-port'},
        Reuse => 1,
    ) or die "Can't start http listener at $O{'listen-host'}:$O{'listen-port'}";
    
    print "Started HTTP listener at " . $d->url . "\n";
    
    my %chld;
    
    if ($O{'listen-clients'}) {
        $SIG{CHLD} = sub {
            # checkout finished children
            while ((my $kid = waitpid(-1, WNOHANG)) > 0) {
                delete $chld{$kid};
            }
        };
    }
    
    while (1) {
        if ($O{'listen-clients'}) {
            # prefork all at once
            for (scalar(keys %chld) .. $O{'listen-clients'} - 1 ) {
                my $pid = fork;
    
                if (!defined $pid) { # error
                    die "Can't fork for http child $_: $!";
                }
                if ($pid) { # parent
                    $chld{$pid} = 1;
                }
                else { # child
                    $_ = 'DEFAULT' for @SIG{qw/ INT TERM CHLD /};
                    http_child($d);
                    exit;
                }
            }
    
            sleep 1;
        }
        else {
            http_child($d);
        }
    
    }
    
    sub http_child {
        my $d = shift;
    
        my $i;
        my $css = <<CSS;
            form { display: inline; }
    CSS
    
        while (++$i < $O{'listen-max-req-per-child'}) {
            my $c = $d->accept or last;
            my $r = $c->get_request(1) or last;
            $c->autoflush(1);
    
            print sprintf("[%s] %s %s\n", $c->peerhost, $r->method, $r->uri->as_string);
    
            my %FORM = $r->uri->query_form();
    
            if ($r->uri->path eq '/') {
                _http_response($c, { content_type => 'text/html' },
                    start_html(
                        -title => HOSTNAME,
                        -encoding => 'utf-8',
                        -style => { -code => $css },
                    ),
                    p('Here are all input parameters:'),
                    pre(Data::Dumper->Dump([\%FORM],['FORM'])),
                    (map { p(a({ href => $_->[0] }, $_->[1])) }
                        ['/', 'Home'],
                        ['/ping', 'Ping the simple text/plain content'],
                        ['/error', 'Sample error page'],
                        ['/other', 'Sample not found page'],
                    ),
                    end_html(),
                )
            }
            elsif ($r->uri->path eq '/ping') {
                _http_response($c, { content_type => 'text/plain' }, 1);
            }
            elsif ($r->uri->path eq '/error') {
                my $error = 'AAAAAAAAA! My server error!';
                _http_error($c, RC_INTERNAL_SERVER_ERROR, $error);
                die $error;
            }
            else {
                _http_error($c, RC_NOT_FOUND);
            }
    
            $c->close();
            undef $c;
        }
    }
    
    sub _http_error {
        my ($c, $code, $msg) = @_;
    
        $c->send_error($code, $msg);
    }
    
    sub _http_response {
        my $c = shift;
        my $options = shift;
    
        $c->send_response(
            HTTP::Response->new(
                RC_OK,
                undef,
                [
                    'Content-Type' => $options->{content_type},
                    'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
                    'Pragma' => 'no-cache',
                    'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT',
                ],
                join("\n", @_),
            )
        );
    }
    

    【讨论】:

    • 我登录只是为了说大声笑@'AAAAAAAAA! My server error!' - +1!
    • 感谢您发布此信息!很好的例子!
    【解决方案2】:

    documentation for HTTP::Daemon中有一个很好的例子。

    【讨论】:

      【解决方案3】:

      符合来自HTTP::Daemon 的 synopsys 的客户端示例:

       require LWP::UserAgent;
      
       my $ua = LWP::UserAgent->new;
       $ua->timeout(10);
       $ua->env_proxy;
      
       my $response = $ua->get('http://localhost:52798/xyzzy');
      
       if ($response->is_success) {
           print $response->decoded_content;  # or whatever
       }
       else {
           die $response->status_line;
       }
      

      您只需要调整端口,也许还需要调整主机。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-14
      • 2014-09-02
      • 2012-04-08
      • 2018-12-11
      • 1970-01-01
      • 2020-05-16
      相关资源
      最近更新 更多