Добрый день! Сегодня я бы хотел описать принцип работы с сокетами в Perl. Вообще говоря, поддержка сокетов существует лишь в современных языках, ориентированных на протоколы Internet. Perl оказался в их числе (еще бы, Perl и Internet, имхо, просто созданы друг для друга). По определению, сокеты — конечные пункты в процессе обмена данными. Для простоты понимания, возьмем систему — «розетка-штепсель». Пока штепсель не воткнется в розетку, ток не пойдет по проводам и не замкнет цепь. Также устроены и сокеты. Одна сторона («розетка») обеспечивает подключение методом слежения порта, а другая («вилка») способна подключится к первой стороне, и принимать/отправлять данные. 

Как известно сокеты делятся на два типа: потоковые (TCP, SOCK_STREAM) и датаграммные (UDP, SOCK_DGRAM). Первый тип обеспечивает надежную коммуникацию без каких-либо потерь данных. Второй тип не гарантирует полную передачу данных, но зато наиболее удобен в плане скорости (нет проверки на точную доставку пакета).

По областям сокеты делят на сокеты Интернета (параметры: IP и порт, PF_INET) и сокеты UNIX (параметры: файл-сокет в системе, PF_UNIX).

Perl, как любой уважающий себя язык, содержит встроенные функции для создания сокетов, но я думаю, что внедрение модулей и объектно-ориентированного программирования в Perl никому не повредило, поэтому буду использовать в описании мой любимый модуль IO::Socket. В данной статье я буду рассматривать потоковые сокеты Интернет (IO::Socket::INET).

Создание сокета

Для создания сокета, в первую очередь нужно подключить в скрипт модуль IO::Socket (фактическое местоположение: IO/Socket.pm относительно директории с библиотеками и модулями Perl). Затем нужно заполнить важные поля объекта, с помощью вызова конструктора new(). Обязательным полем к заполнению является параметр сокета, как написано выше — это IP адрес (который может фигурировать, как hostname и port). Например такая конструкция будет вполне верна (для создания клиента TCP): 

$socket = IO::Socket::INET->new("www.ru:80")

Хотя, иногда мало одного поля, бывает нужно описать некоторые другие свойства сокета (таймаут на подключение, протокол). Вот наиболее полное заполнение параметров конструктора для TCP-клиента:

$socket = IO::Socket::INET->new(PeerAddr=> «www.ru»,
PeerPort => 80,
Proto => ‘tcp’,
Timeout => 50,
Type => SOCK_STREAM) || die «error $!\n»;

Где переменная $! сообщит ошибку в том случае, если подключение не состоялось.

Иными будут выглядеть параметры конструктора при написании TCP-сервера (который открывает порт для подключения). Его структура будет примерно следующей:

$socket = IO::Socket::INET->new(LocalPort => 31337,
Type => ‘tcp’,
Reuse => 1,
Listen => 10) || die «error $!\n»;

Где поля имеют следующее значение:

LocalPort — непосредственно порт, который открывается для слежения.
Reuse — способность сокета перезапускаться при каждом подключении.
Listen — максимальное количество открытых потоков сервера.

Подключение в режиме клиента происходит сразу же после создания сокета. В режиме сервера
клиент считается подключенным после достижения метода $socket->accept. Это выглядит примерно следующим образом:

while($client = $socket->accept()) {
print $client «Welcome to my server\n»;
}

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

Получить ip-адрес клиента можно следующим алгоритмом: идентифицировать клиент, и получить из этих данных его ip-адрес. Это будет выглядеть примерно следующим образом:

$my($prip)=getpeername($client);
($port,$ipaddr)=unpack_sockaddr_in($prip);
$ipaddr= inet_ntoa($ipaddr);

Прием/передача данных

Самый простой способ приема и передачи данных через сокет, являются стандартные операторы print и получение данных из STDIN — <>.
Рассмотрим небольшой пример, а именно передачу в сокет hello world и прием оттуда ответа.

$socket = IO::Socket::INET->new(«www.ru:80»);

print $socket «Hello world\n»;
chomp($answer=<$socket>);

Символ сброса строки «\n» обязателен, так как без него данные не смогут попасть на сервер.

Добиться передачи данных без их буферизации можно отключив ее методом autoflush: $socket->autoflush(1). После этого данные будут автоматически определены без предварительной буферизации.

Закрытие сокета происходит файловой процедурой close(), параметром которой является идентификатор сокета.

Вот самые простые сведения о работе с сокетами в Perl. Далее, я постараюсь описать теорию о разветвляющихся многопоточных серверах и демонах, а также о межпроцессорном взаимодействии и обработке сигналов при создании сокетов.

Оставить мнение

Check Also

Скрытая сила пробела. Эксплуатируем критическую уязвимость в Apache Tomcat

В этой статье мы поговорим о баге в Apache Tomcat, популярнейшем веб-сервере для сайтов на…