<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mysyslog.ru &#187; perl</title>
	<atom:link href="http://mysyslog.ru/posts/tag/perl/feed" rel="self" type="application/rss+xml" />
	<link>http://mysyslog.ru</link>
	<description>Всякая IT всячина</description>
	<lastBuildDate>Thu, 08 Sep 2011 09:29:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Разработка сетевых программ на Perl</title>
		<link>http://mysyslog.ru/posts/416</link>
		<comments>http://mysyslog.ru/posts/416#comments</comments>
		<pubDate>Thu, 15 Apr 2010 14:39:41 +0000</pubDate>
		<dc:creator>constantine.malov</dc:creator>
				<category><![CDATA[Прочитать]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mysyslog.ru/?p=416</guid>
		<description><![CDATA[Очень толковая книга! Перед тем, как начинать писать что-то на perl для сети, советую, прочтите эту книгу. Поверьте, число граблей, на которые вы наступите сократиться в разы.
Написана понятным и легко читаемым язык, что также немало важно. Часто читая в метро отвратительно написанную техническую книгу, ловил себя на том, что уже как минимум полстраницы не понимаю, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ozon.ru/context/detail/id/845797/?partner=mysyslog"><img class="alignleft" style="margin: 5px;" title="Разработка сетевых программ на Perl" src="http://www.ozon.ru/multimedia/books_covers/1000000707.jpg" alt="" width="200" height="284" /></a>Очень толковая книга! Перед тем, как начинать писать что-то на perl для сети, советую, прочтите эту книгу. Поверьте, число граблей, на которые вы наступите сократиться в разы.</p>
<p>Написана понятным и легко читаемым язык, что также немало важно. Часто читая в метро отвратительно написанную техническую книгу, ловил себя на том, что уже как минимум полстраницы не понимаю, что читаю и да и общее состояние мозга близко ко сну. С этой же книгой спать не хочется!</p>
<p>Особенно интересны главы о написании собственных TCP серверов. Очень подробно и на пальцах рассказывается про основные подходы к обработке нескольких одновременных клиентских запросов: fork, prefork, потоковый и мультиплексный. Причем дается не только пример кода, но и хорошая теоретическая база.  </p>
<p>Ссылка на OZON:<br />
<a href="http://www.ozon.ru/context/detail/id/845797/?partner=mysyslog">Разработка сетевых программ на Perl</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mysyslog.ru/posts/416/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>xinetd для сетевой службы на perl</title>
		<link>http://mysyslog.ru/posts/43</link>
		<comments>http://mysyslog.ru/posts/43#comments</comments>
		<pubDate>Sun, 28 Dec 2008 17:43:10 +0000</pubDate>
		<dc:creator>constantine.malov</dc:creator>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://mysyslog.ru/?p=43</guid>
		<description><![CDATA[Вообще говоря в статье про tcp сервер на perl мы занимались изобретением велосипеда. Потому что все уже сделано за нас и мы могли спокойно сосредоточиться на логике приложения, не думаю о fork(), сокетах и т.п.

Напишам небольшую сетевую службу, которая будет принимать сообщение от пользователя и отвечать на него принятой строкой. Если в строчке, полученной от [...]]]></description>
			<content:encoded><![CDATA[<p>Вообще говоря в <a href="http://mysyslog.ru/?p=3">статье про tcp сервер на perl</a> мы занимались изобретением велосипеда. Потому что все уже сделано за нас и мы могли спокойно сосредоточиться на логике приложения, не думаю о fork(), сокетах и т.п.</p>
<p><span id="more-43"></span></p>
<p>Напишам небольшую сетевую службу, которая будет принимать сообщение от пользователя и отвечать на него принятой строкой. Если в строчке, полученной от пользователя будет только одна точка, то службы завершит свою работу.</p>
<pre lang="perl">#!/usr/bin/perl -w
use strict;

$| = 1;
while( my $line = <STDIN> )
{
    $line =~ s/\r?\n$//;
    if ($line =~ /^\.$/)
    {
    die "shutting down\n";
    }
    print "You send to me: $line\n";
}</pre>
<p>Из интересного здесь $| = 1 , эта специальная переменная, которая управляет сбросом буферов вывода на диск. Если она установлена в 0, то интерактивной работы у нас не получится.<br />
Теперь нужно настроить xinetd. Я не стал с ним разбираться, взял настройки от ftp. Создаем файл /etc/xinet.d/my-service</p>
<pre lang="perl">service my-server
{
        disable = no
        flags = REUSE
        socket_type = stream
        instances = 5
        wait = no
        user = root
        server = /root/my-service.pl
}</pre>
<p>Далее прописываем в /etc/services строчку:</p>
<pre lang="perl">my-server       3333/tcp</pre>
<p>Дальше достаточно перезапустить xinetd. </p>
]]></content:encoded>
			<wfw:commentRss>http://mysyslog.ru/posts/43/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>tcp сервер на perl</title>
		<link>http://mysyslog.ru/posts/3</link>
		<comments>http://mysyslog.ru/posts/3#comments</comments>
		<pubDate>Sat, 20 Dec 2008 21:34:48 +0000</pubDate>
		<dc:creator>constantine.malov</dc:creator>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mysyslog.ru/?p=3</guid>
		<description><![CDATA[Для построения распределенных систем есть несколько часто используемых протоколов, например SOAP или XML-RPС. Можно придумать что-то свое или использовать базу данных. В любом случае для сетевого взаимодействия понадобится какая-то служба. Тут тоже можно изобрести велосипед и написать свой tcp сервер. В данной статье я расскажу как написать свой tcp сервер на perl.

На самом деле tcp [...]]]></description>
			<content:encoded><![CDATA[<p>Для построения распределенных систем есть несколько часто используемых протоколов, например SOAP или XML-RPС. Можно придумать что-то свое или использовать базу данных. В любом случае для сетевого взаимодействия понадобится какая-то служба. Тут тоже можно изобрести велосипед и написать свой tcp сервер. В данной статье я расскажу как написать свой tcp сервер на perl.</p>
<p><span id="more-3"></span></p>
<p>На самом деле tcp сервер написал другой человек, но мне через какое-то время нужно было в нем разобраться&#8230; и я ничего не понял. После этого я решил разобраться с этим вопросом.</p>
<p>Поиски в гугле ничего интересного не дал, было несколько интересных ссылок с примерами, но все они были без детального объяснения. Потому я решил подойти к вопросу с другой стороны, и стал искать статьи о сетевом программировании на perl. Через какое-то время я нашел книгу &#8220;Сетевое программирование на perl&#8221; (Network Programming with Perl) Линкольна Стина (Lincoln D. Stein), в которой было все очень хорошо и досконально написано. Дальнейшее повествование &#8211; вольный пересказ соответствующих глав книги.</p>
<p>Сперва немного теории. Мы будем писать forking сервер, т.е. наш сервер будет представлять из себя родительский процесс, порождающий дочерние процессы для обработки каждого нового соединения. Есть и другие варианты реализации сетевых служб: мультипоточные и мультиплексные сервера. Но мы их касаться не будем.</p>
<p>Расскажу о логике работы нашего forking сервера.</p>
<ol>
<li>Родительский процесс создает сокет и ждем входящие соединения от клиентов</li>
<li>Если клиент подключается к сокеты, то родительский процесс принимает соединение.</li>
<li>Сама интересная часть. После установления соединения, родительский процесс порождает дочерний, который является точной копией родительского, т.е. в нем есть и только что принятое соединение и значит дочерний процесс его может обработать.</li>
<li>Родительский процесс у себя закрывает открытое соединение (его теперь обрабатывает его ребенок) и возвращается к ожиданию нового подключения. Если приходит новый клиент &#8211; повторяются пункты 1-4.</li>
<li>А в это время дочерний процесс обменивается данными с клиентом. Когда говорить уже им не о чем, процесс завершает свою работу.</li>
</ol>
<p>Звучит все достаточно просто? На деле все как всегда несколько иначе.  И виноваты в этом зомби. Дело в том, что fork() создает из родительского процесса точную его копию. Так появляется дочерний процесс, который может существовать отдельно от родителя. Но связь между ними остается. Все как в жизни.</p>
<p>Когда дочерний процесс завершает свою работу, то он не исчезает на самом деле. Он остается в списке процессов системы до тех пор, пока родитель не считает его код завершения работы.  Для этого используются вызовы wait() и waitpid(). Если родитель не будет использовать эти вызовы, то рано или позно таблица процессов ОС переполнится и ядро перестанет создавать новые процессы. А нам такой работы не нужно.  Потому родительский процесс должен корректно обрабатывать прекращение работы его потомков, более того, знать чем закончилась работа потомка полезно.</p>
<p>Здесь мы плавно переходим к теме обработки сигналов. Помните я говорил о связи между родительским и дочерним процессом? Для этой связи используются сигналы. Если статус любого ребенка меняется, то родителю отсылается сигнал CHLD . Причем какой имеено дочерний процесс прекратил свое существование сигнал не сообщает, только вызов wait() родительским процессом позволит определить ребенка.</p>
<p>Теперь попробуем собрать все вместе в коде:</p>
<pre lang="perl">#!/usr/bin/perl -w

use strict;
use IO::Socket;
use POSIX 'WNOHANG';

my $port = 3333;
my $bind = '127.0.0.1';
my $work = 1;

$SIG{INT} = sub { $work--; };
$SIG{CHLD} = sub { while ( waitpid(-1,WNOHANG) &gt; 0 ) {} };

my $lsocket = IO::Socket::INET-&gt;new(
        LocalPort =&gt; $port,
        Listen =&gt; 20,
        Proto =&gt; 'tcp',
        Bind =&gt; $bind,
        Reuse =&gt; 1,
        Timeout =&gt; 3600,
);

if (!$lsocket) {
        die "Can't create socket";
}

while ($work) {
        next unless my $connection = $lsocket-&gt;accept;

        defined (my $pid = fork()) or die "Can't fork new child: $!";
        if ($pid == 0) {
                $lsocket-&gt;close;
                serve_client($connection);
                exit 0;
        }

        $connection-&gt;close;
}

sub serve_client {
        my $sock = shift;
        STDIN-&gt;fdopen($sock, "&lt;") or die "Can't reopen STDIN: $!";
        STDOUT-&gt;fdopen($sock, "&gt;") or die "Can't reopen STDOUT: $!";
        STDERR-&gt;fdopen($sock, "&gt;") or die "Can't reopen STDERR: $!";
        $|=1;
        print(STDOUT "Hello!n");
        sleep 10;
}</pre>
<p>Давайте разберем код. В строчках 1-9 подключаются нужные модули и объявляется несколько переменных. Из интересного здесь use POSIX &#8216;WNOHANG&#8217;. Эта константа будет использоваться в флагах waitpid().<br />
Строчки 11-12 примечательны. Здесь мы добавляем обработку сигналов INT позволяет нам &#8220;красиво&#8221; завершить работу сервера. С CHLD все несколько сложнее. Дело в том, что CHLD посылается родительскому процессу без указания pid процесса, завершившего свою работу. Потому waitpid() вызывается с параметром -1, т.е. обработке подлежит любой дочерний процесс, завершивший свою работу. Более того, может случиться так, что одновременно завершит свою работу два или более дочерних процессов, а систему сигналов UNIX в единицу времени может отослать только один сигнал. Потому если просто запустить waitpid(), не все процессы могут быть обработаны&#8230; Чтобы справится с этим waitpid() запускается в цикле пока возвращает положительные значения. Флаг WNOHANG делает вызов waitpid() неблокирующим, т.е. скрипт не будет ожидать, пока появится завершивший свою работу дочерний процесс.<br />
В строчках 14-25 нет ничего сложного, открывается сокет для прослушивания соединений.<br />
В цикле 27-35 сосредоточена вся работа сервера. Родительский процесс ожидает подключения (вызов accept()), если поступает новое соединение выполняется вызов fork(). Родительский процесс отличается от дочернего переменной $pid. У дочернего она равна 0. Этим можно воспользоваться, чтобы отделить код родителя и потомков. Если $pid == 0, то мы закрываем сокет(его все равно слушает родитель) и вызываем функцию serve_client(), о ней чуть позже. После чего завершаем работу потомка. Если же $pid &gt; 0, то мы опять оказываемся в коде родителя. Здесь нам нужно закрыть соединение, его обрабатывает дочерний процесс. После возвращаемся в начало цикла.<br />
Функция serve_client() в строчках 40-48 содержит собственно общение с клиентом, из важного здесь &#8211; переоткрытие потоков stderr stdin srdout на сокет, получаемый через аргумент функции.<br />
На этом все &#8211; получаем рабочий сервер на perl.<br />
А теперь <strong>зачем так не нужно было делать. </strong>На свете есть масса того, что еще стоит написать, зачем же переписывать одно и тоже по сто раз? Это как раз тот случай. Во-первых есть <a href="http://search.cpan.org/search?query=Net%3A%3Aserver%3A%3Afork&#038;mode=all">Net::Server::Fork</a>, во вторых есть inetd, который за вас переоткрывает потоки ввода вывода и позволяет забыть о всей сетевой части, сосредоточившись только на логике вашего приложения.</p>
]]></content:encoded>
			<wfw:commentRss>http://mysyslog.ru/posts/3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

