Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: разработка для Web > Раздача media-файлов через сценарий


Автор: n4n0bit 19.11.2008, 18:22
Стоит задача раздавать файлы через http, но при этом должно быть так "Один Линк" => "Один Пользователь" я это реализовал в модуле http://search.cpan.org/~nanobit/HTTP-DownloadLimit/ . Вкратце скачка осуществляется по такой схеме:

Код

...
...
$| = 1;

binmode FH; binmode STDOUT;

open( FH, '<', 'File.avi' ) or die $!;
while( read FH, my $buf, 2048 )
{
    print $buf;
}
close FH;
...
...


Тестировал я на Apache 2.2 и все было хорошо, но стала задача перейти на LigHTTPD и при использовании своего модуля процесс LigHTTPD потребляет при одном клиенте 16-25 % CPU, а ОЗУ так это вообще всю, такое впечатление что когда работает сценарий и те байты который он отдает клиенту помещаются в ОЗУ и там остаются. Далее настает светлый момент когда сервер падает без записей в логах.

*Пробывал изменять буффер в read() и это положительного результата не дало.

*Проблему с потреблением ресурсов хорошо решает Time::HiRes "sleep" помещая ее в блок while, но разве это коректно? Она же приостонавливает весь сценарий...Этот вариант мне не шибко нравиться, но он работает.

*Может как то сделать чтения кусками? при помощи seek() + временные файлы? но будет ли тут скорость и меньше нагрузка?

ps: OS FreeBSD, Файла размером до 9Gb
pps: помогите с решением проблемы.

Автор: tolkien 20.11.2008, 14:03
Может попробывать вынести из цикла my buf

Код

my $buf = ' ' x 2048;

while( read FH, $buf, 2048 )
{
    print $buf;
}


Автор: n4n0bit 20.11.2008, 14:13
Нет (

Автор: tolkien 20.11.2008, 18:45
Отключить буферизацию у FH

Код


open( FH, '<', 'File.avi' ) or die $!;
my $oh = select(FH);
$|=1;
select($oh);
while( read FH, my $buf, 2048 )
{
    print $buf;
}
close FH;


Автор: n4n0bit 20.11.2008, 20:38
Это тож пробывал - не помогает. единственное что буффер подобрал 32768 при этом если читать локально без сервера и выводить на STDOUT CPU жрет уже до 8% ( FreeBSD/ufs ) а в убунте на ext3 2% почему так пока не узнал но явно что та с фс не учел.

Ну а с сервером по прежнему оперативу жрет ( lighttpd )..

ps: продолжаю пока думать в этом плане..

Автор: ginnie 21.11.2008, 12:56
n4n0bit, как Вы используете модуль в lighttpd и как он использовался в Apache?

Не может ли lighttpd целиком кэшировать ответ модуля? Что происходит если отдавать небольшие файлы в несколько мегабайт?

Автор: n4n0bit 21.11.2008, 13:13
Всмысле как используется? 

Не может ли lighttpd целиком кэшировать ответ модуля? <<< мне кажется что так и происходит.

Автор: ginnie 21.11.2008, 13:21
Цитата(n4n0bit @  21.11.2008,  13:13 Найти цитируемый пост)
Всмысле как используется?

Ни разу не пользовался lighttpd, он разве умеет выполнять CGI? Поэтому задал вопрос, как используется модуль вместе с lighttpd: через FastCGI или может lighttpd сам умеет perl-модули запускать, как nginx?

Автор: n4n0bit 21.11.2008, 15:24
В нем есть http://http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModCGI

Автор: n4n0bit 26.11.2008, 23:53
Еще раз повторюсь, я использовал Apache 2.2 на котором проблем не было и Lighttpd 1.4.19.

Я попробывал выполнить СИ-шный код под Lighttpd:
Код


#include <stdio.h>
#include <fcntl.h>

#define BUFSIZE 4096
#define FILENAME "/home/n4n/_Video/Blade_3.mkv"

int main()
{
    char data[BUFSIZE];
    int n, fd;
    
    if( (fd = open( FILENAME, O_RDONLY, 0)) == 0 )
    {
    printf("open error");
    return;
    }
    
    while(( n = read(fd, data, BUFSIZE)) > 0 )
    write(1, data, n);
        
    return 0;
}


Заключение: 


CGI/ANSI C
ОЗУ и CPU в норме.
CGI/PERL
Пологаю, что mod_cgi плохо работает с PERL при вот такой потоковой раздаче, а именно как бы отправленные байты клиенту еще и кеиширует в ОЗУ, и размер потребляемой памяти одним процессом достигал 1Гб. Процесс использует 25-60% CPU 
OS
FreeBSD 7.0

ps: буду тестировать на др легковесных серверах

Автор: Usmanec 24.2.2009, 16:05
n4n0bit, и не стыдно? Взяли готовый скрипт Daniil Downloader http://softsearch.ru/programs/210-495-daniil-downloader-download.shtml, чуть подредактировали и выложили на CPAN в единоличном авторстве.
Код

#!/usr/bin/perl
####################################
#          perl-script             #
#     Downloader версия 1.01       #
#                                  #
# Авторские права: Путилин Даниил  #
#                  putilin@smtp.ru #
# Посвещаю: Репиной Анастасии из   #
#           г.Усмань Липецкой обл. #
####################################

@raz=('zip','rar','gz','mp3');
$b=25;#Порция в Kb
#######################################
#     НАСТРОЙКА И ИСПОЛЬЗОВАНИЕ       #
#  Вся настройка скрипта заключается  #
# в указании пути до Perl, и задании  #
# разрешенных для загрузки расширений #
# в массиве @raz (смотреть выше)!!!!  #
#  В использовании все так же просто! #
# Объясняю на примере: допустим вы    #
# установили данный скрипт по следую-  #
#  щему URL:                            #
# ваш_сервер/cgi-bin/nph-download.cgi    #
# и вам нужно закочать файл с URL:        #
# ваш_сервер/file.zip, для этого надо      #
# обратиться по адресу:                     #
#ваш_сервер/cgi-bin/nph-download.cgi/file.zip#
#              ВСЁ!!!                         #
###############################################

$|=1;

sub download(){
if(exists($ENV{'HTTP_RANGE'})){
 print "HTTP/1.1 206 Partial Content\r\n";
 $bytes=$ENV{'HTTP_RANGE'};
 $bytes=~s/bytes=//;
 $bytes=~s/\-//;
 $range=1;
}else{
 print "HTTP/1.1 200 Ok\n";
 $bytes=0;
}
$file=$ENV{'PATH_TRANSLATED'};
if(!open(H,$file)){ &error('405 File Not Open',"File ($ENV{'PATH_INFO'}) Not Open");}
binmode(H);
binmode(STDOUT);
#seek(H, 0, 2);
#$size=tell(H);
$size=-s $file;
print "X-Scripts: Downloader/1.0\r\n";
print "Accept-Ranges: bytes\r\n";
$siz=$size-$bytes;
$sizes=$size-1;
print "Content-Length: $siz\r\n";
if($range){print "Content-Range: bytes $bytes-$sizes/$size\r\n";}
print "Content-Type: application/x-downloader-file; name=\"$filename\"\r\n";
print "\r\n";
seek(H, $bytes, 0);
$b=$b*1024;
while(!$x){
 if($size <= $b){$b=$size;$x=1;}
 if(read(H,$h,$b)){$size=$size-$b;}
 print $h;
 }
close(H);
}
sub main{
 print "HTTP/1.1 200 Ok\r\n";
 print "Content-Type: text/html\r\n\r\n";
 print "<html>\n<head>\n<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">\n<title>Downloader 1.01 :: DEMO</title>\n</head>\n";
 print "<body>\n<center><h1>Downloader 1.01</h1>\n<hr>";
 print "<hr></center>Вот вам <a href='/download/np2003.zip'>ссылка архива</a> для испытаний данного скрипта.(В архиве лежит программа налогоплательшик 2003)<br>\nА вот <a href='/cgi-bin/nph-d.cgi/download/np2003.zip'>тот же архив</a> только загружается c помощью данного скрипта.<br>
А сам скрипт находится <a href='/cgi-bin/nph-d.cgi/download/downloader.zip'>здесь</a>!!!<br> УДАЧИ ИСПЫТАТЕЛЯМ!!!
<hr><center><img src=\"/cgi-bin/count/counter.cgi\"></center></body>\n";
 print "</html>";
}
sub error{
 local($kod,$text)=@_;
 print "HTTP/1.1 $kod\n";
 print "Content-Type: text/html\r\n\r\n";
 print "<html>\n<head>\n<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">\n<title>perl-script Downloader 1.01 :: $kod </title>\n</head>\n";
 print "<body>\n<center><h1>perl-script Downloader 1.01</h1><hr><h2> $kod </h2><h3> $text </h3>\n<hr>";
 print "</center>\n</body>\n</html>";
}
if(!exists($ENV{'PATH_INFO'})){&main;}
else{
$filename=$ENV{'PATH_INFO'};
$filename=~s/.*\///;
$rashiren=$ENV{'PATH_INFO'};
$rashiren=~s/.+\.//;
$okey='0';
foreach(@raz){
if($rashiren eq $_){$okey='1';}
}
if($okey eq '0'){&error('403 Forbidden',"Файл <a href='$ENV{PATH_INFO}'>$filename</a> не разрешен для загрузки ([$rashiren])");}
elsif(!-e $ENV{'PATH_TRANSLATED'}){&error('404 File Not Found',"Файл <a href='$ENV{PATH_INFO}'>$filename</a> не найден");}
elsif(!-r $ENV{'PATH_TRANSLATED'}){&error('405 File Not Read',"Файл <a href='$ENV{PATH_INFO}'>$filename</a> не доступен для чтения");}
else{&download;}
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)