Pull to refresh

Comments 46

А это идея, bash вроде умеет работать с сокетами :)
По моему уже был веб-сервер на баше и даже на шеле, стоит спросить гугл.
while :;do nc -p8080 -vnlc'r=read;e=«echo -e»;$r a b c;while [ -n "`$e $a|tr -d "\r\n"`" ];do $r a;done;f=`$e $b|sed s/.//`;h=«HTTP/1.0»;z=«404 Not Found\n»;[ -z $f ]&&(ls|while $r n;do [ -f $n ]&&$e "$n";done)||([ -f $f ]&&($e "$h 200 OK\r\nContent-Type: `file -ib $f`\n";cat $f)||$e "$h $z\n$z")';done

Источник, если хабрапарсер закушает кавычки: alexey.sveshnikov.ru/blog/2007/08/30/bash-httpd-2/
С год или два назад на ЛОРе проскакивал. Если не ошибаюсь, catap его писал (возможно, тот самый catap).
я не понял, а почему код не картинкой? если программа на перл, то или фигурка сисястой девушки, или пивные бутылки, или еще что-нибудь, у кого на что фантазии хватит. думал в перле такая индентация…
:)
В текущем виде проще объяснить что к чему и проще понять что да как ;)

> думал в перле такая индентация…
Кроме отступов для «картинки» нужны и символы подходящие
UFO just landed and posted this here
Поделитесь, чем «преобразовывали»
UFO just landed and posted this here
1. Уолл Л., Кристиансен Т., Орвант Д. Программирование на Perl — шедевр а не книга
UFO just landed and posted this here
2. Learning Perl
3. Шварц Р., Фой Б., Феникс Т. Perl — изучаем глубже.2-е изд
4. High order Perl
UFO just landed and posted this here
Пока я спал уже ответили :)
В июле вышла книга «The difinitive guide to Catalyst» Kieren Diment and Matt S Trout
Вместо
use LWP::Socket;
use FCGI::ProcManager
лучше использовать Net::Server
а вместо этого — use HTTP::Daemon
именно :) настоящий perl way:
— захотелось что-то сделать? найди уже делающий это модуль на CPAN и успокойся
хех…
Аккуратно, не проверяется запрашиваемое имя файла… дырищааа, запроси /etc/passwd и получишь :)

P.S. но вообще то уже давно есть (gentoo dev-perl/HTTP-Server-Simple под лицензией Artistic GPL-2)
UFO just landed and posted this here
А это и не web-сервер, а просто пример скрипта ;) Он не предназначен для использования на продакшен-серверах. Это скорее серверная часть, которая по запросу может делать что ей скажут, в данном случае отдавать любой запрошенный файл. Я сперва сделал, чтобы файл брался только из папки со скриптом, но решил не удлинять код и оставил то, что сейчас в посте :)
У вас HTTP протокол нарушается.

Я бы кстати не стал использовать вот такое «на коленке», когда есть полнеценный и навороченный Perlbal. Это не считая фреймворков для написания своих серверов (HTTP::Daemon, HTTP::Server, AnyEvent::HTTPD, ...).
Ну и к тому же здесь уже была серия статей «пишем fcgi приложение».
А такой вопрос. Мне нужно чтоб по любому запросу отсылался файл нулевого содержания.
Правильно ли я сделал, т.е. вместо этой части
    if ( $file_name ) {
        if ( -f $file_name and open FILE, '<', $file_name ) {
            # Read from file
            $content = join "", <FILE>;
            close FILE;
        }
        else {
            $content = "File not found";
            $stat = 404;
        }

Использую эту?

    if ( open FILE, '<', "/tmp/null" ) {
        $content = join "", <FILE>; close FILE;
вам нужно вместо этого написать $content = ''
Пасиба. Вечером испытаем на кошках
вместо join "", можно использовать конструкцию

$content = do { local $/; <$f> }
> $content = join "",;

не оптимально, лутше файл читать по частям и писать сразу, а не копить в переменной.

Сперва думал проверять размер файла, большой — читать и сразу писать, маленький читать полностью, но это немного увеличило бы кол-во кода.
#!/usr/bin/perl

use strict;
use warnings;
$|++;


use IO::Socket::INET;
use EV;


my $sock = IO::Socket::INET->new(Listen => 10000, LocalPort => 8882, Blocking => 0, Proto => 'tcp') or die "Can't bind : $@\n";

my @evs;
push(@evs,EV::io $sock,EV::READ,\&accept);

sub accept
{
        my $newsock = $sock->accept;
        $newsock->blocking(0);
        push(@evs,EV::io $newsock,EV::READ,\&request);
        $evs[-1]->data(scalar(@evs)-1);
};

sub request
{
        my $data;
        $_[0]->fh->sysread($data,128);

        my $content = "HTTP/1.1 200 OK\r\n"
                        . "Server: EV/2009-09-12\r\n"
                        . "Content-Type: text/html\r\n"
                        . "Connection: close\r\n\r\n"
                        . "<html><body><h1>Hello from Habr</h1></body></html>";
        $_[0]->fh->syswrite($content);
        $_[0]->fh->close;
        undef $evs[$_[0]->data()];
        undef $_[0];
};


EV::loop();

1 поток:
#ab -n 10000 -c 30 http://localhost:8882/

Requests per second: 7099.00 [#/sec] (mean)

пример очень упрощен, отсутсвуют какие либо проверки, но скорость говорит за себя
если ещё добавить prefork…


Не там скорость меряете ;)
Уберите из «поста» чтение из сокета и обращение к диску, подозреваю, что скорость заметно увеличится…

> пример очень упрощен
от того и скорость :)
Не понимаю чего Вы хотите этим сказать, но Вы продолжаете не там мерять скорость… У Вашего скрипта немного другой функционал, да и про «железо» Вы забыли, вряд ли оно у нас савпадает.

Код из поста, но 10 child'ов

$ siege -c 30 -b -f _urls
Transaction rate: 3847.76 trans/sec
Successful transactions: 25193
Failed transactions: 0

$ siege -c 30 -b -i -f _urls
Transaction rate: 3783.66 trans/sec
Successful transactions: 119578
Failed transactions: 0

$ ab2 -n 10000 -c 30 httр://127.0.0.1:8080/
Requests per second: 3900.84 [#/sec] (mean)

Перебираемые урлы — «главная страница», несуществующая страница, существующая страница
Как видите, скорость не сильно различается.

«Облегчённый сервер»
(просто выдача «приветствия»)

$ siege -c 30 -b 127.0.0.1:8080
Transaction rate: 4867.47 trans/sec
Successful transactions: 36506
Failed transactions: 0

$ ab2 -n 10000 -c 30 httр://127.0.0.1:8080/
Requests per second: 5647.83 [#/sec] (mean)


Ваш код
(копипаст и изменение порта)

$ siege -c 30 -b 127.0.0.1:8080
Transaction rate: 3111.36 trans/sec
Successful transactions: 15059
Failed transactions: 0

$ ab2 -n 10000 -c 30 httр://127.0.0.1:8080/
Requests per second: 3201.50 [#/sec] (mean)
А если в вашем коде исправить:
EV: error in callback (ignoring): Modification of a read-only value attempted at tmp.pl line 51.
т.е. убрать строку
undef $_[0];
то результат увеличится примерно на тысячу ;)

Попробуйте на своём компьютере, результаты должны быть ещё выше.
* «облегчённый сервер» работает в один поток, забыл это сразу указать
Код из топика не претендует на идеальный, самый быстрый и самый правильный. Я старался продемонстрировать простоту и лаконичность perl'а. И если уж сокращать функционал и код, то на мой взгляд приведённый ниже код будет более предпочтителен для новичка.

  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use LWP::Socket;
  7.  
  8. my $sock = new LWP::Socket();
  9. die "Can't bind a socket" unless $sock->bind('127.0.0.1', '8080');
  10. $sock->listen(10);
  11.  
  12. while ( my $socket = $sock->accept(3) ) {
  13.     $socket->write( "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n"
  14.                                . "<html><body><h1>Hello from Habr</h1></body></html>" );
  15.     $socket->shutdown();
  16. }
  17.  
  18. $sock->shutdown();


P.S. Я не имею ничего против Вашего кода, не поймите меня неправильно, я просто поясняю идею поста. Если Вы с таким написанием несложного кода несогласны, напишите пост на эту тему, с удовольствием почитаю (думаю, что не только я один).
Хорошую скорость при очень малых ресурсах, можно получить используя неблокирующие сокеты.

На счёт чтения файла по кускам; к этому следует также запрещать буферизацию вывода.
Ну к коду всё-таки надо относиться не как к образцовому написанию сетевого приложения :) Здесь я пытался показать, что не такой уж и страшный perl, его не надо бояться, написать код на перле можно различными способами, в том числе и так, чтобы всё нормально читалось… А "$|++;" пришлось бы поподробнее описывать и чтобы всё было совсем хорошо не помешало описать и прочие предопределённый переменные, типа $/, $_, $!, $', а это уже в этой статье будет лишним.
это к теме non-blocking web server
Sign up to leave a comment.

Articles