Глава 17 Сокеты

Сокеты

Введение

Сокеты являются "конечными пунктами" в процессе обмена данными. Один типы сокетов обеспечивают надежный обмен данными, другие почти ничего не т'л рантируют, зато обеспечивают низкий расход системных ресурсов. Обмен данными через сокеты может осуществлятьс
В этой главе мы рассмотрим два самых распространенных типа сокетов: потоковые и датаграммные. Потоковые сокеты обеспечивают двусторонние, последовательные и надежные коммуникации; они похожи на каналы (pipes). Датаграммные сокеты не обеспечивают после Сокеты делятся по областям (domain): сокеты Интернета и сокеты UNIX. Имя сокета Интернета содержит две составляющие: хост (IP-адрес в определенном формате) и номер порта. В мире UNIX сокеты представляют собой файлы (например, /tmp/mysock).
Кроме области и типа, с сокетом также ассоциируется определенный протокол. Протоколы не имеют особого значения для рядового программиста, поскольку для конкретного сочетания области и типа сокета редко используется более одного протокола.
Области и типы обычно идентифицируются числовыми константами (котормг возвращаются функциями, экспортируемыми модулями Socket и IO::Socket). Потоковые сокеты имеют тип SOCK_STREAM, а датаграммные - SOCK_DGRAM. Области Интернета соответствует константа существующих программ). Используйте символические имена вместо числовых значений, поскольку последние могут измениться (что неоднократно происходило).
Имена протоколов (например, tcp и udp) тоже соответствуют числам, используемым операционной системой. Встроенная функция Perl getprotobyname возвращает номер по имени протокола. Если функциям сокетов передается значение 0, система выберет подходящий п
Perl содержит встроенные функции для создания сокетов и управления ими; они в основном дублируют свои прототипы на С. Хотя это удобно для получения низкоуровневого, прямого доступа к системе, большинство предпочитает работать с более удобными средствами. На помощь приходят классы IO::Socket::INET и IO::Socket::UNIX - они обес Начнем с рассмотрения встроенных функций. В случае ошибки все они возвращают undef и присваивают $! соответствующее значение. Функция socket создает сокет, bind - назначает ему локальное имя, connect - подключает локальный сокет к другому (возможно, удале
Типичный сервер вызывает socket, bind и listen, после чего в цикле вызывает accept в блокирующем режиме, ожидая входящих подключений (см. рецепты 17.2 и 17.5). Типичный клиент вызывает socket и connect (см. рецепты 17.1 и 17.4). Да-таграммные клиенты
При вызове bind, connect или send для конкретного приемника необходимо указать имя сокета. Имя сокета Интернета состоит из хоста (IP-адрес, упакованныи функцией inet_aton) и порта (числа), объединенных в С-подобную структуру функцией sockaddr_in:
use Socket;
$packed_ip = inet_aton("208.146.240.1");
$socket_name = sockaddr_ln($port, $packed_ip);
Имя сокета UNIX представляет собой имя файла, упакованное в структуру С функцией
sockaddr_un:
use Socket;
$socket_name = sockaddr_un("/tmp/mysock");
Чтобы преобразовать упакованное имя сокета и снова получить имя файла или пару "хост/порт", вызовите sockaddr_un или sockaddr_in в списковом контексте:
($port, $packed_ip) = sockaddr_in($socket_name); # Для сокетов PF_INET ($filename)
= sockaddf_un($socket_name): # Для сокетов PF_UNIX
Функция inet_ntoa преобразует упакованный IP-адрес в ASCII-строку.
$ip_address = inet_ntoa($packed_ip);
$packed_ip = inet_aton("204.148.40.9");
$packed_ip = inet_aton("www.oreilly.com");

В большинстве рецептов используются сокеты Интернета, однако практически все сказанное в равной мере относится и к сокетам UNIX. В рецепте 17.6 объясняются отличия и возможные расхождения.
Сокеты являются основой для работы сетевых серверов. Мы рассмотрим три варианта построения серверов: в нервом для каждого входящего подключения создается порожденный процесс (рецепт 17.11), во втором сервер создает порожденные процессы заранее (рецепт Некоторые серверы должны одновременно вести прослушивание но многим IP-адресам (см. рецепт 17.14). Хорошо написанный сервер деинициализируется и перезапускается при получении сигнала HUP; в рецепте 17.16 показано, как реализовать такое поведение в Perl. К

17.1. Написание клиента TCP

Проблема

Вы хотите подключиться к сокету на удаленном компьютере.

Решение

Следующее решение предполагает, что связь осуществляется через Интернет TCP-подобные коммуникации на одном компьютере рассматриваются в рецепте 17.G, Либо воспользуйтесь стандартным (для версии 5.004) классом IO::Socket::INET:
use 10::Socket;
$socket = 10::Socket::INET->new(PeerAddr =>
$remote_host, PeerPort => $remote_port, Proto =>
"tcp", Type =>
SOCK_STREAM) or die "Couldn't connect to $remote_host:$remote_port : $@\n";
# . . . Сделать что-то с сокетом
print $socket "Why don't you call me anymore?\n";
$answer = <$socket>;
# Отключиться после завершения
close($socket):

либо создайте сокет вручную, чтобы лучше управлять его поведением:
use Socket;
# Создать сокет
socket(SERVER, PFJNET, SOCK_STREAM, getprotobyname('tcp'));
# Построить адрес удаленного компьютера
$internet_addr = inet_aton($remote_host)
or die "Couldn't convert $remote_host into an Internet address: $!\n";
$paddr = sockaddr_in($remote_port, $internet_addr);
# Подключиться connect(TO_SERVER, $paddr)
or die "Couldn't connect to $remote_host:$remote_port : $!\n";
# ... Сделать что-то с сокетом
print TO_SERVER "Why don't you call me anymore?\n";
# И отключиться после завершения
close(TCLSERVER);

Комментарий

Ручное кодирование состоит из множества действий, а класс IO::Socket::INET объединяет их все в удобном конструкторе. Главное, что необходимо знать, - куда вы направляетесь (параметры PeerAddr и PeerPort) и каким образом (параметр Type). По переданной инфо Параметр PeerAddr содержит строку с именем хоста ("www. o'reilly. corn") или его IP-адресом ('204.148.40.9"). PeerPort - целое число, номер порта для нолк.-почг ния. Номер порта можно включить в адрес в виде "www. oreilly. corn: 80". Параметр Type определ Чтобы подключиться через SOCK_STREAM к порту конкретного компьютера, не поддерживающего других возможностей, передайте 10: : Socket: : INET->new одну строку с именем хоста и портом, разделенными двоеточием:
$client = 10::Socket::INET->new("www.yahoo.com:80") or die $@;

При возникновении ошибки IO::Socket::INET возвращает undef, а переменной $? (не $ ) присваивается сообщение об ошибке.
$s = 10::Socket::INET->new(PeerAddr => "Does not Exist", Peerport => 80,
Type => SOCK_STREAM ) or die $@;

Если ваши пакеты бесследно исчезают в глубинах сети, вероятно, невозможность подключения к порту будет обнаружена лишь через некоторое время. Вы можете уменьшить этот промежуток, передавая параметр Timeout при вызове 10::Socket::INET->new():
$s = 10::Socket::INET->new(PeerAddr => "bad.host.com", PeerPort => 80,
Type => SOCK_STREAM, Timeout => 5 )
or die

Но в этом случае вы уже не сможете использовать $! или $@, чтобы узнать причину неудачи - невозможность подключения или тайм-аут. Иногда бывает удобнее установить тайм-аут вручную, без использования модуля.
INADDR_ANY - специальный адрес, означающий "прослушивание на всех интерфейсах". Если вы хотите ограничить его конкретным IP-адресом, включите параметр LocalAddr в вызов 10:: Socket:: INET->new. При ручном кодировании это делается так:
$inet_addr = inet_aton("208.146.240.1");
$paddr = sockaddr_in($port, $inet_addr);
bind(SOCKET, $paddr) or die "bind: $!";

Если вам известно только имя, действуйте следующим образом:
$inet_addr = gethostbyname("www.yahoo.com")
or die "Can't resolve www.yahoo.com: $!";
$paddr = sockaddr_in($port, $inet_addr);
bind(SOCKET, $paddr) or die "bind: $!":

> Смотри также -------------------------------
Описание функций socket, bind, connect и gethostbyname в perlfunc(\); документация по стандартным модулям Socket, IO::Socket и Net::hostent; раздел "Internet TCP Clients and Servers" perlipc(1)\ рецепты 17.2-17.3.

17.2. Написание сервера TCP

Проблема

Вы хотите написать сервер, который ожидает подключения клиентов по сети к определенному порту.

Решение

Следующее решение предполагает, что связь осуществляется через Интернет. TCP-подобные коммуникации на одном компьютере рассматриваются в рецепте 17.6. Воспользуйтесь стандартным (для версии 5.004) классом IO::Socket::INET:
use 10::Socket;
$server = 10::Socket::INET->new(LocalPort => $server_port,
Type => SOCK_STREAM, Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port : $@i\n";
while ($client = $server->accept()) { # $client - новое подключение
}
close($server);

Или создайте сокет вручную, что позволит получить полный контроль над ним:
use Socket;
# Создать сокет
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
# Чтобы мы могли быстро перезапустить сервер
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
# Построить свой адрес сокета
$my_addr = sockaddr_in($server_port, INADDR_ANY);
bind(SERVER, $my_addr)
or die "Couldn't bind to port $server_port : $!\n";
# Установить очередь для входящих соединений
$sten(SERVER, SOMAXCONN)
or die "Couldn't listen on port
$server_port : $!\n";
# Принимать и обрабатывать подключения
while (accept(CLIENT, SERVER)) {
# Сделать что-то с CLIENT
}

close(SERVER);

Комментарий

Написать сервер сложнее, чем клиент. Необязательная функция listen сообщае'1 операционной системе, сколько подключений могут находиться в очереди к серверу, ожидая обслуживания. Функция setsockopt, использованная в решении, позволяет избежать двухминутног
Числовой аргумент listen определяет количество не принятых функцией accept подключений, которые будут поставлены в очередь операционной системой перед тем, как клиенты начнут получать ошибки "отказ в обслуживании". Исторически максимальное значение эт
Функции accept передаются два аргумента: файловый манипулятор, подключаемый к удаленному клиенту, и файловый манипулятор сервера. Она возвращает IP-адрес и порт клиента, упакованные
inet_ntoa:
use Socket;
while ($client_address = accept(CLIENT, SERVER)) {
(Sport, $packed_ip) = sockaddr_in($client^address);
$dotted_quad = inet_ntoa($packed_ip);
# Обработать }
В классах IO::Socket accept является методом, вызываемым для манипулятора сервера:
while (($client,$client_address) = $server->accept()) {
# ...
}

Если ожидающих подключений нет, программа блокируется на вызове accept до того, как появится подключение. Если вы хотите гарантировать, что вызов accept не будет блокироваться, воспользуйтесь неблокирующими сокетами:
use Fcnti qw(F_GETFL F_SETFL 0_NONBLOCK);
$tlags = fcntl($SERVER, F_GETFL, 0)
or die "Can't get flags for the socket: $!\n":
$flags = fcntl($SERVER, F_SETFL, $flags | 0_NONBLOCK)
or die "Can't set flags for the socket: $!\n";

Если теперь при вызове accept не окажется ожидающих подключений, ассе]. вернет undef и присвоит $! значение EWOULDBLOCK.
Может показаться, что при возвращении нулевых флагов от F_GETFL будет вызвана функция die, как и при неудачном вызове, возвращающем undef. Это не гак - неошибочное возвращаемое значение fcnti, как и для iocti, преобразуется Perl в специальное значение

Смотри также -------------------------------
Описание функций socket, bind, listen, accept, fcnti и setsockopt в peiifunc(1) страницы руководства socket(2), setsockopt(2) вашей системы (если они есть); документация по стандартным модулям Socket, IO::Socket и Net::hostent; раздел "Internet TCP Clients and Servers" perlipc(1), рецепты 7.13-7.14; 17.1; 17.3; 17.7.

17.3. Передача данных через TCP

Проблема

Требуется передать или принять данные по TCP-соединению.

Решение

Следующее решение предполагает, что связь осуществляется через Интернет. TCP-подобные коммуникации на одном компьютере рассматриваются в рецепте 17.6.
Первый вариант - print или ':
print SERVER "What is your name?\n";
chomp ($response = );

Второй вариант - функции send и recv:
defined (send(SERVER, $data_to_send, $flags)) or die "Can't send : $!\n";
recv(SERVER, $data_read, $maxlen, $flags) or die "Can't receive: $!\n";

Третий вариант - соответствующие методы объекта IO::Socket:
use 10::Socket;
$server->send($data_to_send, $flags) or die "Can't send: $!\n";
$server->recv($data_read, $flags) or die "Can't recv: $!\n";

Чтобы узнать, могут ли быть получены или приняты данные, воспользуйтесь функцией select, для которой в классе IO::Socket также предусмотрена удобная оболочка:
use 10::Select;
$select = 10::Select->new();
$select->add(*FROM_SERVER);
$select->add($to_client);
@read_from = $select->can_read($timeout);
foreach $socket (@read_from) {
# Прочитать ожидающие данные из
$socket }

Комментарий

Сокеты используются в двух принципиально различных типах ввода/вывода, каждый из которых обладает своими достоинствами и недостатками. Стандартные функции ввода/вывода Perl, используемые для файлов (кроме seek и sysseek), работают и для потоковых сокетов, При программировании сокетов очень важно помнить о буферизации. Хотя буферизация и была спроектирована для повышения быстродействия, она может повлиять на интерактивное поведение некоторых программ. Если при вводе данных с помощью о будет обнаружен раздел
Вероятно, для клиентов и серверов с построчным обменом данных это подходит - при условии, что вы не забыли включить автоматическую очистку буфера. Новые версии IO::Socket делают это автоматически для анонимных 4)айловых манипуляторов, возвращаемых 10:
Но стандартный ввод/вывод - не единственный источник буферизации. Операции вывода (print, printf, syswrite - или send для сокета TCP) буферизуются на уровне операционной системы по так называемому алгоритму Нейгла. Если пакет данных отправлен, но еще
use Socket;
require "sys/socket.ph"; # Для &TCP_NODELAY
setsockopt(SOCKET, SOL_SOCKET, &TCP_NODELAY, 1)
or die "Couldn't disable Nagle's algorithm: $!\n";

Ее повторное включение происходит так:
setsockopt(SOCKET, SOL_SOCKET, &TCP_NODELAY, 0)
or die "Couldn't enable Nagle's algorithm: $!\n";

Как правило, TCP_NODELAY все же лучше не указывать. Буферизация TCP существует не зря, поэтому не отключайте ее без крайней необходимости - например, если ваше приложение работает в режиме реального времени с крайне интенсивным обменом пакетов. TCP_NODELAY загружается из sys/socket.ph - этот файл не устанавливается автоматически вместе с Perl, но может быть легко построен. Подробности приведены в рецепте 12.14. Буферизация чрезвычайно важна, поэтому в вашем распоряжении имеется функция select. Она определяет, какие манипуляторы содержат непрочитанный ввод, в какие манипуляторы возможна запись и для каких имеются необработанные "исключительные состояния". Функция
$rin = ''; # Инициализировать маску
vec($rin, fileno(SOCKET), 1) = 1; # Пометить SOCKET в $rin
# Повторить вызовы vec() для каждого проверяемого сокета
$timeout =10: # Подождать 10 секунд
$nfound = select($rout = $rin, undef, undef, $timeout);
if (vec($rout, fileno(socket),1)){
# В SOCKET имеются данные для чтения
}

Функция select вызывается с четырьмя аргументами. Три из них представляют собой битовые маски: первая проверяет в манипуляторах наличие непрочитанных данных в манипуляторах; вторая - возможность безопасной записи без блокировки; третья - наличие в них
Функция модифицирует передаваемые ей маски, поэтому при выходе из нее биты будут установлены лишь для манипуляторов, готовых к вводу/выводу. Отсюда один стандартный прием - входная маска ($rin в предыдущем примере) присваивается выходной ($rout), чтоб
Нулевой тайм-аут определяет режим опроса (проверка без блокировки). Некоторые начинающие программисты не любят блокировки, и в их программах выполняется "занятое ожидание"
(busy-wait) - программа в цикле выполняет опрос, снова и снова. Когда прогр
Поскольку select использует битовые маски, которые утомительно создавать и трудно интерпретировать, в решении используется стандартный модуль IO::Select. Он обходит работу с битовыми масками и, как правило, более удобен. Полное объяснение исключительных состояний, проверяемых третьей маской select, выходит за рамки настоящей книги.
Другие флаги send и recv перечислены в страницах руководства этих системных функций.

> Смотри также -------------------------------
Описание функций send, recv, fileno, vec и setsockopt в perlfunc(1); разделы "I/O Operators" и "Bitwise String Operators" Bperlop(1); страница руководства setsockopt(2) вашей системы (если есть); документация по стандартным модулям Socket и IO::Socket рецепты 17.1-17.2.

17.4. Создание клиента UDP

Проблема

Вы хотите обмениваться сообщениями с другим процессом, используя UDP (датаграммы).

Решение

Чтобы создать манипулятор для сокета UDP, воспользуйтесь либо низкоуровневым модулем Socket для уже существующего манипулятора:
use Socket;
socket(SockHandle, PF_INET, SOCK_DGRAM,
getprotobyname("udp")) or die "socket: $!";
либо модулем IO::Socket, возвращающим анонимный манипулятор:
use 10::Socket;
$handle = 10::Socket::INET->new(Proto => 'udp')
or die "socket: $@"; # Да, здесь используется $@
Отправка сообщения на компьютер с именем $HOSTNAME и адресом порта $PORTNO выполняется так:
$ipaddr = inet_aton($HOSTNAME);
$portaddr = sockaddr_in($PORTNO, $ipaddr);
send(SockHandle, $MSG, 0, $portaddr) == length($MSG)
or die "cannot send to $HOSTNAME($PORTNO): $!";
Получение сообщения, длина которого не превышает $MAXLEN:
$portadd-r = recv(SockHandle, $MSG, $MAXLEN, 0) or die "recv: $!";
($portno, $ipaddr) = sockaddr_in($portaddr);
$host = gethostbyaddr($ipaddr, AF_INET);
print "$host($portno) said $MSG\n";

Комментарий

Датаграммные сокеты не похожи на потоковые. Поток создает иллюзию посте янного соединения. Он напоминает телефонный звонок - установка связи обходится дорого, но в дальнейшем связь надежна и проста в использовании. Датаграммы больше похожи на почту - если
Если датаграммы настолько ненадежны, зачем же ими пользоваться? Просто некоторые приложения наиболее логично реализуются с применением датаграмм. Например, при пересылке аудиоданных важнее сохранить поток в целом, чем гарантировать прохождение каждого
Поскольку датаграммы не создают иллюзии постоянного соединения, в работе с ними вы располагаете несколько большей свободной. Вам не придется вызывать connect для подключения сокета к удаленной точке, с которой вы обмениваетесь данными. Вместо этого ка
send(MYSOCKET, $msg_buffer, $flags, $remote_addr) or die "Can't send: $!\n";

Единственный часто используемый флаг, MSG_OOB, позволяет отправлять и принимать внеполосные (out-of-band) данные в нетривиальных приложениях. Удаленный адрес ($remote_addr) должен представлять собой комбинацию порта и адреса Интернета, возвращаемую функцией sockaddr_in модуля Socket. Если хотите, вызовите connect для этого адреса - в этом случае последний аргумент при вызове send можно опускать
В примере 17.1 приведена небольшая программа, использующая протокол UDP. Она устанавливает связь с портом времени UDP на компьютере, имя которого задается в командной строке, или по умолчанию на локальном компьютере. Программа работает не на всех комп
Пример 17.1. clockdrift
#!/usr/bin/perl
# clockdri
# - сравнение текущего времени с другой системой
use strict;
use Socket:
my ($host, $him, $src, Sport, $ipaddr, $ptime, $delta);
my $SECS_of_70_YEARS = 2_208_988_800;
socket(MsgBox, PF_INET, SOCK_DGRAM, getprotobyname("udp"))
or die "socket: $!";
$him = sockaddr_in(scalar(getservbyname("time", "udp")),
inet_aton(shift || '127.1'));
derined(send(MsgBox, 0, 0, $him))
or die "send: $!";
defined($src = recv(MsgBox, $ptime, 4, 0)) or die "recv: $!";
(Sport-, $ipaddr) = sockaddr_in($src);
$host = gethostbyaddr($ipaddr, AF_INET);
my $delta = (unpack("N", $ptime) - $SECS_of_70_YEARS) - time();
print "Clock on $host is $delta seconds ahead of this one.\n";

Если компьютер, с которым вы пытаетесь связаться, не работает или ответ потерям, программа застрянет при вызове recv в ожидании ответа, который никогда не придет.

Смотри также --------------------------------
Описание функций send, recv, gethostbyaddr и unpack в perlfunc(1); документация по стандартным модулям Socket и IO::Socket; раздел "UDP: message passing" perlipc(1); рецепт

17.5. Создание сервера UDP

Проблема

Вы хотите написать сервер UDP.

Решение

Сначала вызовите функцию bind для номера порта, но которому будет осуществляться связь с вашим сервером. С модулем IO::Socket это делается просто:
use 10::Socket;
$server = 10::Socket::INET->new(LocalPort => $server_port,
Proto => "udp")
or die "Couldn't be a udp server on port $server_port : $@\n";

Затем в цикле принимайте сообщения:
while ($him = $server->recv($datagram, $MAX_TO_READ, $flags)) {
# Обработать сообщение
}

Комментарий

Программирование для UDP намного проще, чем для TCP. Вместо того чтобы последовательно принимать клиентские подключения и вступать в долгосрочную связь с клиентом, достаточно просто принимать сообщения от клиентов по мере их поступления. Функция recv возв
В примере 17.2 показан небольшой сервер UDP, который просто ожидает сообщений. Каждый раз, когда приходит очередное сообщение, мы выясняем, кто его послал, и отправляем ответ-сообщение с принятым текстом, после чего сохраняем новое сообщение.
#!/usr/bin/perl -w
# udpqotd - сервер сообщений UDP use strict;
use 10::Socket;
my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO):
$MAXLEN = 1024;
$PORTNO = 5151;
$sock = 10::Socket::INET->new(LocalPort => $PORTNO, Proto => 'udp')
or die "socket: $@";
print "Awaiting UDP messages on port $PORTNO\n";
$oldinsg = "This is the starting message.";
while ($sock->recv($newmsg, $MAXLEN)) {
my($port, $ipaddr) = sockaddr_in($sock->peername):
$hishost = gethostbyaddr($ipaddr, AF_INET);
print "Client $hishost said ''$newmsg'"\n";.
$sock->send($oldmsg);
$oldmsg = "[$hishost] $newmsg":
} die "recv: $!";

С использованием модуля IO::Socket программа получается проще, чем с низкоуровневым модулем Socket. Нам не приходится указывать, куда отправить сообщение, поскольку библиотека сама определяет отправителя последнего сообщения и сохраняет его в объекте Программа telnet не подходит для общения с этим сервером; для этого необходим специальный клиент. Один из вариантов приведен в примере 17.3. Пример 17.3. udpmsg
#!/usr/bin/perl -w
# udpmsg - отправка сообщения серверу udpquotd
use 10::Socket;
use strict;
my($sock, $server_host, Smsg, Sport, $ipaddr, $hishost, $MAXLEN, $PORTNO, $TIMEOUT);
$MAXLEN = 1024;
$PORTNO = 5151;
$TIMEOUT = 5;
$server_host = shift;
Smsg = "@ARGV";
$sock = 10::Socket::INET->new(Proto => 'udp',
PeerPort => $PORTNO,
PeerAddr => $server_host)
Пример 17.3 (продолжение)
or die "Creating socket: $!\n";
$sock->send($msg) or die "send: $!";
eval {
local $SIG{ALRM} = sub { die "alarm time out" };
alarm $TIMEOUT;
$sock->recv($msg, $MAXLEN) or die "recv: $!";
alarm 0;
1; # Нормальное возвращаемое значение
eval } or die "recv from $server_host timed out after $TIMEOUT seconds.\n";
(Sport, $ipaddr) = sockaddr_in($sock->peername);
$hishost = gethostbyaddr($ipaddr, AF_INET);
print "Server $hishost responded ''$msg''\n";
При создании сокета мы с самого начала указываем хост и номер порта, что по зволяет опустить эти данные при вызовах send.
Тайм-аут (alarm) был добавлен на случай, если сервер не отвечает или вообще не работает. Поскольку recv является блокирующей системной функцией, выход из которой может и не произойти, мы включаем ее в стандартный блок eval для прерывания блокировки по

> Смотри также -------------------------------
Описание функций send, recv и alarm в perlfunc(l); документация по стандартным модулям Socket и IO::Socket; раздел "UDP: message passing" perlipc(1); рецепты 16.21; 17.4.
© copyright 2000 Soft group

Используются технологии uCoz