Опубликован: 28.09.2007 | Уровень: специалист | Доступ: платный
Лекция 4:

Сокеты

При написании программ на персональной ЭВМ, например, на С++ или ассемблере, существует возможность выбора модели памяти: small, medium, compact, large или huge. Эти модели отличаются друг от друга числом сегментов (по 64 Кбайт) памяти, выделяемой для программы и данных. Модель small предполагает, что все указатели имеют тип near, если явно не указано обратное (не записан модификатор FAR). Модель large считает по умолчанию все указатели дальними, если явно не присутствует модификатор near. В модели huge длина блока данных может превышать размер одного сегмента. С особенностями этих моделей рекомендуется ознакомиться по описаниям конкретных трансляторов. Используя те или иные модели при создании сетевых программ, нужно учитывать проблемы, которые могут возникнуть при переносе вашей программы из одной операционной среды в другую. ОС Unix и Windows не поддерживают каких­-либо моделей памяти, и их система адресации скорее совместима с моделью large. При переносе программы из одной среды в другую об этой проблеме лучше не забывать, и перед началом отладки полезно изучить особенности адресации.

Различие операционных сред особенно заметно при выполнении блокирующих процедур, рассмотренных выше, например, операции сетевого ввода/вывода. Блокирующие процедуры являются потенциальным источником "повисания" программ — скажем, оператор recv может вечно ждать отклика, в то время как удаленный сервер будет ждать сообщения от программы, выполняющей recv. По этой причине создание не блокирующих сокетов представляется привлекательным. Такие сокеты формируются путем вызова стандартного оператора socket с последующим обращением к процедуре, изменяющей режим работы сокета (по умолчанию создается блокирующий сокет). После этого при вызове блокирующего оператора, например, recv, при условии, что сокет не имеет запрашиваемых данных, система возвратит флаг ошибки. Таким образом, при работе с неблокирующим сокетом операционная система проверяет возможность немедленного выполнения процедуры и возвращает сигнал ошибки, если это невозможно. Все операторы winsock являются асинхронными и неблокирующими. Асинхронные операции при невозможности выполнить требуемую операцию не выдают сообщения об ошибке. За тем, чтобы процедура была выполнена так, как нужно, в этом случае следит операционная система. По завершении асинхронной операции ОС Windows посылает сообщение тому окну, из которого эта операция была вызвана. Но и операторы, работающие с неблокирующими сокетами Беркли, также являются неблокирующими. В то же время все операции ввода и вывода в Unix являются синхронными.

Хотя оператор WSAAsyncSelect считается аналогом select, между ними имеется существенное отличие. WSAAsyncSelect — единственный оператор, использующий дескриптор сокета в качестве параметра. Если select контролирует состояние нескольких сокетов, то для того, чтобы достичь того же результата с помощью wsaasyncselect, надо реализовать столько вызовов, сколько сокетов мы хотим мониторить. Форма обращения к WSAAsyncSelect имеет вид:

WSAAsyncSelect (SOCKETs, HWND hWnd, unsigned int wMsg, long lEvent),

где sдескриптор сокета, состояние которого мы хотим контролировать, аргумент, hWndдескриптор окна получателя сообщения; wMsg определяет тип посылаемого сообщения (эти два параметра являются стандартными для всех функций Windows); lEvent — битовая маска, определяющая тип событий, которые нас интересуют. Возможные значения параметра lEvent приведены в таблице 4.6.

Таблица 4.6. Возможные значения параметра lEvent оператора WSAAsyncSelect
значение назначение
FD READ Готовность к чтению
FD WRITE Готовность к записи
FD OOB Поступление Out_Of_Band данных
SD ACCEPT Контроль установки входного соединения
FD CONNECT Контроль реализованных соединений
FD CLOSE Контроль закрытия соединения

При необходимости контроля комбинации вышеперечисленных состояний эти маски могут объединяться по ИЛИ. Как только состояние сокета станет соответствовать выбранной маске, Windows пошлет прикладной программе соответствующее сообщение. Это сообщение содержит дескриптор окна, откуда осуществлен вызов процедуры WSAAsyncSelect, идентификатор сообщения, а также 16-битовый и 32-битовый параметры этого сообщения. Первый из них представляет собой дескриптор сокета, где это событие произошло. Младшие 16 бит второго параметра являются кодом события, а старшие предназначены для записи кода ошибок, если они произошли.

Как уже было отмечено, обращение к WSAAsyncSelect переводит сокет в неблокирующее состояние. При необходимости реализовать, например, процедуру recv, следует обратиться сначала к WSAAsyncSelect, запросив Windows информировать вас о готовности чтения ( lEvent=FD_READ ). После этого обработчик сообщений windows при получении соответствующего сигнала предоставит возможность прикладной программе перейти к выполнению операции recv. Так как сокет уже получил данные, блокировки не произойдет и программа их немедленно получит.

Особое внимание блокирующим операциям должно быть уделено в старых версиях Windows, поскольку блокировка остановит не только выполнение задачи, вызвавшей эту операцию, но и все другие приложения (ЭВМ станет неуправляемой на время блокировки). Здесь блокирующие процедуры должны быть запрещены, вместо этого при необходимости вызова такой процедуры windows реализует цикл проверки состояния сокета (очереди сообщений). Остальные приложения могут при этом продолжить свою работу, а при получении благоприятного сообщения Windows разрешает выполнение блокирующей процедуры, так как она уже не может вызвать блокировки. Осложнения могут возникнуть, если обработчик сообщений Windows получит сигнал, который приведет к вызову другой блокирующей процедуры. Сегодня в Windows действует правило, запрещающее такие вызовы из прикладных программ, как блокирующие, так и неблокирующие. То есть, на время выполнения блокирующей процедуры все обращения к сетевому интерфейсу запрещены.

Имеется несколько операторов Winsock, предназначенных для работы с блокирующими процедурами (смотри таблицу 4.7).

Таблица 4.7.
WSACancelBlockingCall прерывание блокирующей процедуры (без аргументов)
WSAIsBlocking определение блокирующей операции (без аргументов)
WSASetBlockingHook перехват блокирующего вызова, организация цикла ожидания
WSAUNhookBlockingHook восстановление прежней блокировки

При необходимости прервать блокирующую операцию можно вызвать процедуру WSACancelBlockingCall, прикладная программа получит при этом сообщение об ошибке ( WSAEINTR ). Оператор WSAIsBlocking возвращает значение TRUE, если в данный момент реализуется блокирующая операция. Последние два оператора из четырех названных служат для построения пользовательских обработчиков сообщений.

Аппарат сокетов предполагает возникновение и исчезновение вычислительных и управляющих процессов. Новый процесс может наследовать "старые" сокеты. В этом случае может возникнуть необходимость выяснить адрес партнера, с которым взаимодействует данный сокет. Эту задачу можно решить с помощью команды getpeername(s, destaddr, addrlen), где destaddrуказатель на структуру типа (рис. 4.6):

Указатель на структуру типа для команды getpeername

Рис. 4.6. Указатель на структуру типа для команды getpeername

AF идентифицирует семейство протоколов (для TCP/IP=2 ), для которого порожден данный сокет, вся структура занимает 16 октетов. addrlenуказатель на переменную, куда будет записана длина адреса. Сокет может быть выключен командой close(s), где sидентификатор сокета, который надлежит закрыть. Если пользователь не хочет более посылать или получать данные, он может выдать команду shutdown(s, how), где параметр how может принимать значения: 0 — блокируется прием данных; 1 — блокируется передача данных; 3 — блокируются любые обмены.

Каждое соединение должно иметь свой неповторимый код ISN (Initial Sequence Number). Этот код посылается клиентом серверу с помощью сегмента SYN. Для реализации режима соединения прикладная программа на одном конце канала устанавливается в режим пассивного доступа (passive open), а операционная система на другом конце ставится в режим активного доступа (active open). Протокол TCP предполагает реализацию 11 состояний ( ESTABLISHED, CLOSED, LISTEN, SYN_SENT, SYN_RCVD и т.д.), переход между которыми строго регламентирован (см. описание протокола ТСР выше).

При написании диагностических и управляющих программ в рамках ОС Windows можно использовать простые сокеты (Sock_Raw) или библиотеку ICMP.DLL (эта динамическая библиотека не является частью Win32 API). Библиотека ICMP.DLL содержит, в частности, процедуру ICMPSendEcho, которая посылает запросы эхо по указанному адресу и возвращает отклик в пределах указанного временного интервала. В качестве аргументов запрос ICMPSendEcho использует ICMP-дескриптор, который получается в результате запроса IcmpCreateFile.

Приложение может использовать WSAEnumProtocols для определения того, какой транспортный протокол (стек протоколов) поддерживается, и попутно можно получить дополнительную информацию, которая содержится в структуре WSAPROTOCOL_INFO.

В то время как в WinSock 1.1 имеется только одно семейство адресов AF_INET, включающее в себя ограниченное число известных типов сокетов и идентификаторов протоколов, в WinSock 2 это ограничение снято. Информация по WinSock 2 доступна по адресу:

http://www.ictp.trieste.it/~radionet/nuc1996/ref/winsock/wsspi22.htm

В настоящее время WinSock допускает совмещение по времени нескольких операций ввода/вывода. Такого рода операции возможны только для сокетов, созданных оператором WSASocket с флагом WSA_FLAG_OVERLAPPED=1 (Win32).

Запросы получения и отправки информации возвращают отклик немедленно. Если получен нуль, это означает, что операция ввода/вывода завершилась успешно; если же получен флаг SOCKET_ERROR с кодом ошибки WSA_IO_PENDING — операция начата успешно, последующие сообщения позволят судить о дальнейшем выполнении операции.

Допуская возможность нескольких операций ввода/вывода одновременно, нужно обеспечить соответствие между этими процессами и сообщениями об их завершении. В Winsock эта проблема решена с помощью введения объектов события (event objects), по аналогии с Win32. Эти объекты создаются, уничтожаются, устанавливаются в определенное состояние и т.д. Приложение может использовать оператор WSACreateEvent для создания дескриптора (указателя) объекта события, который передается в качестве обязательного параметра для совмещаемых во времени процедур посылки и получения данных ( WSASend, WSASendTo, WSARecv, WSARecvFrom ). Каждому оператору создания объекта WSACreateEvent должен соответствовать оператор WSACloseEvent, ликвидирующий его. Объекты события используются также оператором WSAEventSelect для того, чтобы связать FD_XXX сетевое события с объектами события.

В 32-разрядной среде операторы для работы с объектами события WSACreateEvent, WSACloseEvent, WSAResetEvent, WSASetEvent, WSAGetOverlappedResult и WSAWaitForMultipleEvents строго соответствуют операторам Win32.

Приложение может установить режим ожидания с блокировкой для одного или нескольких объектов события, используя оператор WSAWaitForMultipleEvents. Для этих целей можно применить и WaitForMultipleObjects. Если при ожидании предпочтительнее отсутствие блокировки, можно воспользоваться оператором WSAGetOverlappedResult, чтобы проконтролировать завершение заданного процесса.

Операторы запуска совмещаемых по времени процессов ввода/вывода WSASend, WSASendTo, WSARecv, WSARecvFrom используют в качестве опционного указателя lpCompletionRoutine, который позволяет по завершении процесса обмена передать управление определенной приложением программе.

Наталья Шульга
Наталья Шульга

Курс "информационная безопасность" .

Можно ли на него записаться на ПЕРЕПОДГОТОВКУ по данному курсу? Выдается ли диплом в бумажном варианте и высылается ли он по почте?

Мария Архипова
Мария Архипова
виктор виноградов
виктор виноградов
Россия, Курская область
Евгений Миловзоров
Евгений Миловзоров
Россия, Пенза, ПГУ, 2004