Интегрированные сети ISDN

         

Winsock (для UNIX, Windows- и -NT)



7.1 Winsock (для UNIX, Windows-95 и -NT)

Какие бы замечательные идеи в области телекоммуникаций, распределенных баз знаний или поисковых систем вам не пришли в голову, реализовать их на практике можно, лишь написав соответствующую программу. Основные операционные среды (Unix, Windows 95, NT или 2000) базируются в настоящее время на идеологии соединителей (socket). Эта технология была разработана в университете г. Беркли (США) для системы Unix, поэтому соединители иногда называют соединителями Беркли (berkeley sockets). Соединители реализуют механизм взаимодействия не только партнеров по телекоммуникациям, но и процессов в ЭВМ вообще (см. [15]). Вопросы сетевого программирования под MS DOS рассмотрены в [24].

Работа с соединителями содержит ряд этапов: соединитель создается, настраивается на заданный режим работы, используется для организации обмена и, наконец, ликвидируется. Технология соединителей поддерживает работу с любыми стеками протоколов, совмещенные процедуры ввода/вывода, использование большого числа сервис-провайдеров (серверов услуг), возможность группирования соединителей, что позволяет реализовать их приоритетное обслуживание, и многое другое. Набор операторов, поддерживающих интерфейс сервис провайдера, образует отдельную динамическую библиотеку.

Для общей синхронизации работы сервис-провайдеров и приложений в winsock введено понятие объектов событий. Объекты событий служат в частности для организации работы совмещенных по времени процессов информационного обмена. Здесь уместно замечание об использовании стандартных номеров портов. В много задачных, многопользовательских системах стандартные номера портов используются при инициализации процесса. Так как допускается несколько идентичных соединений (например, несколько одновременных сессий FTP) между клиентом и сервером, стандартными номерами портов здесь не обойтись. Ведь psips сервера могут соотвествовать несколько pcipc клиента.

В системах, ориентированных на соединение, пара комбинаций IP-адресов и номеров портов однозначно определяет канал связи между двумя процессами в ЭВМ.
Такая комбинация называется соединителем (socket). Номера портов могут и совпадать, так как относятся к разным машинам, но IP-адреса должны быть обязательно разными. Впервые идея соединителя была использована в системе 4.3 BSD Unix для организации сетевого ввода/вывода. В Unix внешнее устройство и файл с точки зрения системного программиста эквивалентны. Сетевые процедуры несколько сложнее и не укладываются в такую простую схему. Из этой простой схемы выпадают, прежде всего, операции, при которых сервер пассивно ожидает обращения особенно для операций обмена не ориентированных на соединение. Соединитель является пограничным понятием между протоколами телекоммуникаций и операционной системой ЭВМ. Соединители играют важную роль при написании прикладных программ (API).

Соединитель отправителя = IP-адрес отправителя + номер порта отправителя

Соединитель адресата = IP-адрес адресата + номер порта адресата

Межкомпьютерные коммуникации не сводятся к знакомству с соседским депозитарием, к выполнению операций Telnet, FTP и т.д. Одной из важнейших задач является удаленный контроль за процессами в больших рассредоточенных системах, когда обмен информацией активизируется не человеком, а ЭВМ. Примерами таких задач могут служить управление современными высокотехнологичными производствами, сбор метео- или другой геофизической информации в реальном масштабе времени, эксперименты в области физики высоких энергий, где для контроля установки и сбора экспериментальных данных используются десятки (а иногда и сотни) вычислительных машин, которые обмениваются диагностической информацией и данными. Именно для решения таких задач и применяются идеи соединителей (sockets), "труб" и т.д.. Понятие соединителя в прикладных программах это не просто комбинация IP-адресов и номеров портов, это указатель на структуру данных, где хранятся параметры виртуального канала. Прежде чем воспользоваться соединителем, его нужно сформировать. Оператор формирования соединителя имеет вид:

s=socket(INT AF, INT type, INT protocol);



где все параметры целочисленные, AF (address_family) - характеризует набор протоколов, соответствующий данному соединителю (это может быть набор Internet, Unix, Appletalk и т.д.). Для Интернет AF может принимать только значение PF_INET, для Unix - PF_UNIX. Аргумент type определяет тип коммуникаций (SOCK_STREAM, SOCK_RAW, и SOCK_DGRAM). Аргумент protocol задает код конкретного протокола из указанного набора (заданного AF), который будет реализован в данном соединении. Протоколы обозначаются символьными константами с префиксом IPPROTO_ (например, IPPROTO_TCP или IPPROTO_UDP). Допускается значение protocol=0 (протокол не указан), в этом случае используется значение по умолчанию для данного вида соединений. Значения AF и type можно обычно найти в файле <sys/socket.h>. Возвращаемый параметр S представляет собой дескриптор соединителя. Параметр SOCK_STREAM говорит о том, что вы намерены создать надежный двунаправленный канал обмена, ориентированный на соединение (TCP для Интернет). Связь c другим процессом в этом случае устанавливается оператором connect. После установления соединения данные могут посылаться оператором send или получаться посредством оператора recv. Параметр SOCK_DGRAM характеризует канал, не ориентированный на соединение, с пакетами фиксированного размера (например, UDP в случае AF= PF_INET). Такой канал позволяет использовать операторы sendto и recvfrom. Параметр SOCK_RAW определяет третий режим, при котором возможно использование протоколов нижнего уровня, например ICMP. Таким образом, формирование соединителя - это создание описывающей его структуры данных.

Если операция socket завершилась успешно, s равно дескриптору соединителя, в противном случае s=INVALID_SOCKET (-1). С помощью оператора WSAGetLastError можно получить код ошибки, проясняющий причину отрицательного результата.



Дескриптор соединителя указывает на элемент таблицы дескрипторов, соответствующий данному соединителю. Оператор socket отводит место в этой таблице. Элемент такой таблицы имеет вид:



Код семейства протоколов;

Код типа сервиса;

Локальный IP-адрес;

Удаленный ipIPадрес;

Номер локального порта;

Номер удаленного порта;

IP-адрес определяет интерфейс ЭВМ, а номер порта в данном случае характеризуют сетевую процедуру.

Так как в Unix возможно формирование соединителя без IP-адресов, а для практической работы они нужны, имеется оператор bind, который позволяет присвоить определенный адрес заданному соединителю:

r=bind(s, const struct socketaddr far*name, int namelen),

где s - целочисленный код дескриптора, параметр name (идентификатор локального адреса) обычно (для Интернет) содержит три величины: IP-адрес ЭВМ, код протокольного набора, номер порта, который определяет характер приложения. Структура адресной информации имеет вид:

struct sockaddr {

u_short sa_family;

char sa_data[14];

};

Параметр namlen определяет длину второго параметра. В рамках этой идеологии легко реализовать систему клиент-сервер. IP-адрес может быть сделан равным INADDR_ANY (или =0), если ЭВМ имеет несколько интерфейсов. При номере порта равным нулю, windows socket присвоит порту уникальный номер в диапазоне 1024-5000. Приложение может выполнить операцию getsockname после bind, чтобы определить присвоенный адрес. Оператор bind выполняется до операций connect или listen. При корректном выполнении оператор bind возвращает код 0 (r=0), в противном случае SOCKET_ERROR=-1. Команда bind выдается для записи собственного номера порта. Сервер генерирует команду bind, чтобы подготовить определенный вид связи (например, FTP), и пассивно ожидает запроса connect со стороны клиента:

R=connect(s, const struct socketaddr FAR*name, int namelen),

где s - дескриптор соединителя, name - идентификатор адреса места назначения (указатель на структуру данных), а namelen - длина этого адреса. Таким образом, оператор connect сообщает ip-адрес и номер порта удаленной ЭВМ. Если адресное поле структуры name содержит нули, оператор connect вернет ошибку WSAEADDRNOTAVAIL (или SOCKET_ERROR=-1).


Установка в режим ожидания осуществляется командой listen, которая организует очередь запросов:

R=listen(s, int backlog),

где backlog - задает максимальный размер очереди для приходящих запросов соединения (то есть сколько запросов может быть принято на обслуживание без потерь, обычно этот параметр равен 5). При переполнении очереди будет послано сообщение об ошибке. Следует иметь в виду, что клиент, ориентированный на соединение, также должен прослушивать порт протокола, ожидая появления дейтограмм-откликов. Ожидающий соединитель посылает каждому отправителю сообщение-отклик, подтверждающее получение запроса на соединение. Оператор listen подготавливает соединитель к обработке потока запросов, система должна быть достаточно быстродействующей. Запросы из очереди извлекаются оператором accept:

R=accept(s, struct sockaddr FAR*addr, int FAR*addrlen),

где s - дескриптор соединителя, который прослушивает соединение (тот же, что и в listen), addr - опционный указатель на структуру, которая содержит адрес, addrlen - код длины адреса. Оператор accept позволяет серверу принять запрос от клиента. Когда входная очередь сформирована, программа реализует процедуру accept и переходит в режим ожидания запросов. Программа извлекает первый элемент очереди, создает новый соединитель со свойствами, идентичными s, и при успешном выполнении возвращает дескриптор нового соединителя. При возникновении ошибки возвращается код INVALID_SOCKET. По окончании обработки запроса сервер вновь вызывает accept, который возвращает ему дескриптор соединителя очередного запроса, если таковой имеется. Если очередь пуста, accept блокирует программу до получения связи. Существуют серверы с параллельной и последовательной обработкой запросов. Параллельный обработчик запросов не ждет завершения обработки предшествующего запроса и вызывает оператор accept немедленно. В системе Unix используются обычно параллельные обработчики запросов.

Схема взаимодействия различных операторов winsock в рамках идеологии клиент/сервер для случая процедур, ориентированных на соединение, показана на рисунке 7.1.Стрелками обозначены направления посылки сетевых сообщений.

Следует иметь в виду, что программе клиента (выделена рамкой) не нужно знать номер порта, по этой причине она не обращается к процедуре bind, а для установления связи сразу вызывает оператор connect. Современные распределенные информационные системы, WWW-серверы, поисковые системы и т.д. эффективно используют механизмы формирования соединителей и многие процедуры, описанные в данном разделе. Из литературы [24] известно, что для многих видов услуг в Интернет выделены строго определенные номера портов. Доступ же к этим услугам должен быть обеспечен достаточно большому числу пользователей. С клиентской стороны при этом используются номера портов со значениями из диапазона 1024-5000. Для каждого нового клиентского запроса в ЭВМ-сервере, как правило, открывается новый процесс.


Содержание раздела