Перл практикум: Сетевые хитрости
(Часть I) Хал Померанз
Эта статья из цикла статей о программировании сетей на Перле. Программирование сетей на Перле очень похоже программированию сетей на C, но конструкции Перла делают это немного проще, чтобы сосредоточиться на фактической работе установки сетевого подключения, а не проблематике, подобно переформатированию данных и обработке особых ситуаций. Люди, которые всегда пугались мистики сетевых приложений, могут часто использовать Перл, чтобы расти вверх; опытные программисты могут использовать Перл, для быстрой сборки прототипов своих сетевых приложений.
Размышление о сетевом программировании
Обсуждения сетевого программирования кажется всегда уводит в лабиринты извилистых небольших акронимов, но основные понятия очень просты. Самые простые сетевые отношения - между двумя хостами: "сервер", который обладает некоторой совокупностью данных и "клиент", который имеет вопрос, и должен испрашивать, чтобы сервер ответил (отсюда "клиент-серверная технология" ). Например, ваш Web-браузер - клиент, который может запросить сервер нашей организации, "какая информация находится на http://www.netmarket.com/? "
Одна полезная аналогия - система развлечений в полете, которые имеют авиалинии. Сервер - система развлечений самолета: имеющая связку данных (музыка из кинофильмов и различные жанры музыки), что может поставляться пассажирам (клиенты). Клиенты должны явно просить относительно информации, однако, подключаясь к паре наушников и набирая небольшой цифровой бип получат тот звук, который они хотят слышать.
Наушники из вышеупомянутой аналогии замещают понятие, которое сетевые программисты называют "сокет". Клиенты устанавливают подключения сокета к серверу, подключая один конец логического канала к серверу на хорошо известном месте (маленькое отверстие у вашего места) с определенным номером порта (набор номера на вашем месте, чтобы получить рок музыку) в тоже время на другом конце канала (находятся наушники на ваших ушах).
Как в моем примере авиалинии, должным образом разработанные сетевые серверы могут одновременно обрабатывать подключения нескольких клиентов. В отличие от моей аналогии, сетевые клиенты могут соединяться с несколькими различными серверами (или в разное время к одному и тому же серверу) одновременно.
Сделаем это
С легкостью самую сложную часть подготовки сокета занимает подготовка структуры двоичных данных, которая сообщает операционной системе c каким сервером надо соединиться. Этот материал выглядит не очень Перл-подобным, потому что мы подготавливаем структуру данных C-типа. Функции Перла для работы с сетями имеют непосредственную связь с библиотекой сокетов языка С.
use Socket;
$server = "www.netmarket.com";
$port = 80;
$server_addr =( gethostbyname($server) )[4];
$server_struct = pack("S n a4 x8", AF_INET, $port, $server_addr);
$proto = (getprotobyname(`tcp'))[2];
socket(MYSOCK, PF_INET, SOCK_STREAM, $proto)
|| die "Failed to initialize socket: $!\n";
connect(MYSOCK, $server_struct)
|| die "Failed to connect() to server: $!\n";
Первая строка этого примера просто подключает модуль сокетов Перла. Этот модуль определяет множество полезных констант, которые используются позже в программе. Затем инициализируем имя сервера, с которым этот клиент войдет в контакт, и сетевой порт, чтобы говорить с портом сервера 80 (случилось, что этот порт серверы сети слушают по умолчанию). Вы могли бы фактически передать эти значения в вашу программу как параметры командной строки, или этот код мог бы стать частью функции, которая получает эти значения как функциональные параметры.
Чтобы иметь возможность подключиться к серверу, программа должна перевести человечески читаемое имя сервера (www.netmarket.com) в сетевой адрес. Функция gethostbyname () разрешает имя сервера и возвращает список информации: сетевой адрес сервера - пятое значение результата (не волнуйтесь о других значениях прямо сейчас).
Структура C-типа создается функцией pack() используя ранее полученный адрес. Эта структура имеет три поля: описание типа сетевого адреса, в остальной части структуры какой адрес порта подключить, и по какому адресу сервера подключиться (остальная часть структуры заполнена нулями). AF_INET - константа, определенная в модуле сокетов Перла, которая представляет тип адреса сети протокола IP (некоторые люди должны использовать другие типы сетей подобно AppleTalk, DECnet, или X.25, все из которых имеют их собственные AF_* константы в Socket.pm). Если программист не определяет тип сетевого подключения в начале структуры, операционная система не способна определится с информацией сетевого адреса в остальной части структуры, и попытка инициализации сокета потерпит неудачу.
С этим безнравственным pack() дела уйдут не туда, за то мы в состоянии произвести настройку фактического сокета. Сначала, клиент инициализирует свою сторону сокета в виде Перловского файлового дескриптора MYSOCK. Другие аргументы функции socket() определяют тип сетевого подключения, образ работы с сокетом, и протокол передачи. PF_INET и другие константы модуля Socket.pm родственные AF_INET определяют сокет IP-типа (на самом деле, изначально, AF_INET использовался как основа двоичной структуры, и функция socket() тут ни причем). SOCK_STREAM - другая константа, которая показывает, что клиент и сервер будут общаться, используя подключение, подобно телефонному разговору - обе стороны могут говорить и слушать друг друга, а подключение остается вплоть до того времени, как одна из сторон не положит трубку. (SOCK_STREAM - основной метод связи, но существуют и другие методы вроде SOCK_DGRAM, который больше походит на получение клиентом сигнального дыма, а сервер может посылать сколь угодно много сообщений, но нет никаких гарантий, что другая сторона их увидит.
Наконец то, протокол передачи определен: обсуждение отличий TCP против UDP - вне рамок этой статьи, но TCP - почти всегда правильный выбор, если Вы беспокоитесь по этому поводу. Всегда используйте getprotobyname (), чтобы получить правильную константу протокола для TCP. Ленивые программисты часто использую жесткую константу привязанную к ядру системы, потому случается, что на клонах UNIX, люди подобные мне, проклинают таких людей.
С одним концом сокета твердо в руке (повторю, файловый дескриптор MYSOCK), клиент вызывает функцию connect() для того, чтобы фактически войти в контакт с сервером. Функция connect() получает свои аргументы - файловый дескриптор и двоичную структуру, подготовленные ранее. Успешное завершение функции connect() является фактом успешного установления сеанса связи клиента с сервером.
Продолжение следует...

О, ты начал
О, ты начал переводить?
Так надо было сразу сказать, мы бы обсудили и договорились, что и что делает. Плюс было бы неплохо получить разрешение на перевод и публикацию.
Народ, кто еще хочет принять участие и вложить немножко труда в общее дело:)?
В меру сил...
Во первых, статьи 10-ти летней давности,
но актуальны и сейчас. О них уже и забыли.
Да и перевод собственный, а не чужой.
Но, статьи классные. Но повторюсь, по мере сил.
Мне сейчас, надо переработь, фак из Яковлев.орг.
А это займет некоторое время. И важнее.