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

Проблема

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

Решение

Следующее решение предполагает, что связь осуществляется через Интернет. Первый вариант — print или <>:
print SERVER "What is your name?\n";
chomp ($response = <SERVER>);
Второй вариант — функции 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:
 IO::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 IO::Select;
$select = IO::Select->new();
$select->add(*FROM_SERVER);
$select->add($to_client);
@read_from = $select->can_read($timeout);
foreach $socket (@read_from) {
  # Прочитать ожидающие данные из $socket
}

Комментарий

Сокеты используются в двух принципиально различных типах ввода/вывода, каждый из которых обладает своими достоинствами и недостатками. Стандартные функции ввода/вывода Perl, используемые для файлов (кроме seek и sysseek), работают и для потоковых сокетов, однако для датаграммных сокетов необходимы системные функции send и recv, работающие с целыми записями.
При программировании сокетов очень важно помнить о буферизации. Хотя буферизация и была спроектирована для повышения быстродействия, она может повлиять на интерактивное поведение некоторых программ. Если при вводе данных с помощью <> будет обнаружен разделитель записей, программа может попытаться прочитать из сокета больше данных, чем доступно в данный момент. И print и <> используют буферы stdio, поэтому без включения автоматической очистки буфера для манипулятора сокета данные не отправятся на другой конец в момент их передачи функцией print. Вместо этого они будут ждать заполнения буфера.
Вероятно, для клиентов и серверов с построчным обменом данных это подходит — при условии, что вы не забыли включить автоматическую очистку буфера. Новые версии IO::Socket делают это автоматически для анонимных файловых манипуляторов, возвращаемых IO::Socket->new.
Но стандартный ввод/вывод — не единственный источник буферизации. Операции вывода (print, printf, syswrite — или send для сокета TCP) буферизуются на уровне операционной системы по так называемому алгоритму Нейгла. Если пакет данных отправлен, но еще не подтвержден, другие передаваемые данные ставятся в очередь и отправляются либо после набора следующего полного пакета либо при получении подтверждения. В некоторых ситуациях (события мыши, оконных системах, нажатия клавиш в приложениях реального времени) такая буферизация оказывается неудобной или попросту неверной. Буферизация Нейгла отключается параметром сокета TCP_NODELAY:
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, но может быть легко построен.
Буферизация чрезвычайно важна, поэтому в вашем распоряжении имеется функция select. Она определяет, какие манипуляторы содержат непрочитанный ввод, в какие манипуляторы возможна запись и для каких имеются необработанные «исключительные состояния». Функция select получает три строки, интерпретируемые как двоичные данные; каждый бит соответствует файловому манипулятору. Типичный вызов 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), чтобы вызов select изменил только $rout и оставил $rin в прежнем состоянии.
Нулевой тайм-аут определяет режим опроса (проверка без блокировки). Некоторые начинающие программисты не любят блокировки, и в их программах выполняется «занятое ожидание» (busy-wait) — программа в цикле выполняет опрос, снова и снова. Когда программа блокируется, операционная система понимает, что процесс ждет ввода, и передает процессорное время другим программам до появления входных данных. Когда программа находится в «занятом ожидании», система не оставляет ее в покое, поскольку программа всегда что-то делает — проверяет ввод! Иногда опрос действительно является правильным решением, но гораздо чаще это не так. Тайм-аут, равный , означает отсутствие тайм-аута, поэтому ваша программа терпеливо блокируется до появления ввода.
Поскольку select использует битовые маски, которые утомительно создавать и трудно интерпретировать, в решении используется стандартный модуль IO::Select. Он обходит работу с битовыми масками и, как правило, более удобен.

См. также

Описание функций send, recv и vec



2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: