Приведенных ниже примеров вполне достаточно, чтобы получить представление о принципах работы
с модулем HTTP::Daemon, и об организации работы простого сервера.
Основной особенностью работы с HTTP::Daemon является то, что функциональность сервера обеспечивается не самим HTTP::Daemon, а массой дополнительных модулей: URI, HTTP::Request, HTTP::Message, HTTP::Headers, HTTP::Response. И для создания даже простого сервера, требуется понимать каждый из них.
- Самый простой пример сервера
- Обработка данных из URL-строки
- Прием данных от клиента
- Передача данных клиенту
- Полезные ссылки
Самый простой пример сервера
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#!/usr/local/bin/perl use HTTP::Daemon; use HTTP::Status; my $d = HTTP::Daemon->new(Timeout => 15) || die; print "Please contact me at: <URL:", $d->url, ">\n"; while (my $c = $d->accept) { $r = $c->get_request; if ($r) { $c->send_basic_header; $c->print("Content-Type: text/plain"); $c->send_crlf; $c->send_crlf; $c->print("Ok\n"); } $c->close; undef($c); } exit; |
Сервер запускается, выводит строку адреса, по которому он готов принимать запросы.
|
1 2 3 |
%perl daemon.pl Please contact me at: <URL:http://dev-lab.info:55190/> |
Если обратиться по указанному адресу (браузером, скриптом), сервер примет запрос и вернет ответ. В данном примере при создании объекта, был задан таймаут. Если по истечении указанного количества секунд к серверу никто не обратится, он завершит свою работу.
Обработка данных из URL-строки
Имеется некая структура данных. Требуется, чтобы сервер возвращал данные из этой структуры,
в зависимости от пришедшего запроса.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
#!/usr/local/bin/perl use CGI; use HTTP::Daemon; use HTTP::Status; my $department = { 'db_group' => { 'Igor' => { 'office' => 315, 'off_phone' => 2341, }, }, 'web_group' => { 'Maria' => { 'office' => 202, 'off_phone' => 2417, }, 'Anastasia' => { 'office' => 202, 'off_phone' => 2419, }, }, }; my $d = HTTP::Daemon->new(Timeout => 20) || die; print "Please contact me at: <URL:", $d->url, ">\n"; while (my $c = $d->accept) { $r = $c->get_request; if ($r) { $c->send_basic_header; $c->print("Content-Type: text/plain"); $c->send_crlf; $c->send_crlf; # разбираем, чего ввел клиент в URL-строке my @url_params = split(/\//, $r->url->path); my $query_params = CGI->new($r->url->query)->Vars; # в зависимости от содержимого URL, определяем: что ответить клиенту if ($url_params[1] && $query_params->{name} && $query_params->{data}) { my $info = $department->{$url_params[1]}->{$query_params->{name}}->{$query_params->{data}}; if ($info) { $c->send_status_line; $c->print($info."\n"); } else { $c->send_status_line(404); } } elsif ($url_params[1] && $query_params->{name}) { my $info = $department->{$url_params[1]}->{$query_params->{name}}; if ($info) { $c->send_status_line; foreach (keys %{$info}) { $c->print($_.":".$info->{$_}."\n"); } } else { $c->send_status_line(404); } } elsif ($url_params[1]) { my $info = $department->{$url_params[1]}; if ($info) { $c->send_status_line; foreach (keys %{$info}) { $c->print($_."\n"); } } else { $c->send_status_line(404); } } else { $c->send_status_line; foreach (keys %{$department}) { $c->print($_."\n"); } } } $c->close; undef($c); } exit; |
Клиент может обратиться к данному серверу, используя адреса типа:
- http://dev-lab.info:56449/ - вывод списка всех групп департамента
- http://dev-lab.info:56449/web_group/ - вывод списка сотрудников заданной группы
- http://dev-lab.info:56449/web_group?name=Maria - вывод всей информации о сотруднике
- http://dev-lab.info:56449/web_group?name=Maria&data=off_phone - вывод запрошенной информации о сотруднике, например, номера внутреннего телефона или номера кабинета
Если запрашиваемые данные в хранилище отсутствуют - клиент получит статус ответа 404.
Прием данных от клиента
Прием данных
|
1 2 3 4 5 6 7 8 9 10 |
while (my $c = $d->accept) { my $request = $c->get_request; if ($request) { ... my $content = $r->content(); ... } $c->close; undef($c); } |
Прием данных из формы
Если серверу была передана форма, и был указан тип данных 'application/x-www-form-urlencoded', сервер может получить эти данные следующим образом:
|
1 2 3 4 5 6 7 8 9 10 |
while (my $c = $d->accept) { my $request = $c->get_request; if ($request) { ... my %query_params = $request->url->query_form; ... } $c->close; undef($c); } |
Метод query_form() вернет данные в виде хеша, где каждый ключ - это name поля формы, а значение - содержимое этого поля.
Передача данных клиенту
Вывод клиенту сообщений об ошибках
Можно выводить клиенту сообщения об ошибках с помощью метода send_error(). Ответ будет выслан в html-формате.
|
1 2 3 4 5 6 |
... $r = $c->get_request; if ($r) { $c->send_error(404, 'Error, text of error'); } ... |
Передача клиенту файлов
Можно в ответ на запрос, предлагать клиенту скачать файл.
|
1 2 3 4 5 6 |
... $r = $c->get_request; if ($r) { $c->send_file_response("file.tsv"); } ... |
Ответ клиенту с помощью HTTP::Response
Можно сформировать и отправить ответ клиенту с помощью HTTP::Response.
|
1 2 3 4 5 6 7 8 9 10 |
... $r = $c->get_request; if ($r) { my $res = HTTP::Response->new(200); $res->header('Content-Type' => 'text/html'); $res->content("OK, all be fine"); $c->send_response($res); } ... |
Полезные ссылки
Документация на search.cpan.org
search.cpan.org: HTTP::Response
search.cpan.org: HTTP::Request
search.cpan.org: URI
Примеры использования HTTP::Daemon
perlmonks.org: GUI with HTTP::Daemon
gist.github.com: Stand-alone directory browser on HTTP::Daemon
snippets.dzone.com: Pre-forking HTTP daemon in Perl