Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
чтиво_ч2.doc
Скачиваний:
4
Добавлен:
15.11.2019
Размер:
284.67 Кб
Скачать

Блокирующие socket’ы

Блокирующие socket’ы самые легкие в использовании, они использовались уже в первых реализациях socket’ов. Когда операция, выполняемая блокирующим socket’ом, не может немедленно завершиться, socket заблокирует основной процесс (т.е. остановит выполнение) до тех пор, пока операция не завершится. Это подразумевает то, что когда Вы вызываете WinSock функции типа send или recv, может потребоваться долгое время (по сравнению с другими API вызовами) до завершения этих функций.

Как Вы можете заметить, как только главный поток вызывает WinSock функцию, которая не может быть быстро закончена, он (поток) будет заблокирован, пока функция не завершит свое выполнение. По умолчанию socket находится в блокирующем режиме и ведет себя так, как показано выше. Как я говорил ранее, тут будут показаны примеры «диалога» программы и WinSock. Для блокирующего socket’а это будет просто:

Программа: «Отправь-ка эти данные» WinSock: «Хорошо, но мне может понадобится некоторое время» ……. ……. ……. «Сделано!»

Polling (последовательный опрос)

В действительности последовательный опрос – очень плохая модель ввода/вывода, но я ее опишу, так сказать «для общего развития». Опрос используется для неблокирующих socket’ов, это значит, что socket сначала должен быть установлен в неблокирующий режим. Это можно сделать с помощью ioctlsocket. Вообще polling повторяет некоторые действия, пока не будет достигнут желаемый результат, в нашем случае будет повторяться WinSock функция, пока она не завершится успешно:

Так как socket неблокирующий, функция не заблокирует основной процесс. Если функция не может выполнить свою задачу – она будет завершена неудачно. Данная модель ввода/вывода будет циклически вызывать функцию, пока она не будет выполнена:

Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа: «Отправь-ка эти данные» WinSock: «Сделано! »

Как я уже говорил, эта модель плоха в использовании, т.к. ее эффект такой же как и эффект блокирующих socket'ов, за исключением того, что Вы можете хоть как-то контролировать цикл вызова функций. Такой стиль синхронизации называется «активное ожидание» (busy waiting), это значит, что программа «занята» ожиданием, затрачивая драгоценные ресурсы процессора. Блокирующие socket’ы более эффективны, т.к. у них другой режим ожидания. Они не используют цикл и тем самым не сильно напрягают процессор.

Теперь Вы знаете, как работает модель «последовательный опрос». Но я советую Вам скорее забыть эти знания и избегать их дальнейшего использования =).

Select (Выбор)

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

Диалог программы и WinSock будет следующим:

Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа: «Хорошо, скажешь мне, когда будет наилучший момент, чтоб повторить попытку» WinSock: «Конечно, повиси минутку» … … «Пробуй снова!» Программа: «Отправь-ка эти данные» WinSock: «Сделано!»

Вы, возможно, заметили, что эта модель выглядит подобно блокирующему socket’у. Это, потому что select действительно блокирует. Первый вызов пытается выполнить WinSock операцию. В этом случае операция заблокировала бы выполнение основного процесса, но функция не может быть выполнена и она завершается неудачей. Тогда управление передается основному потоку программы, который, в свою очередь, вызывает select-метод (т.е. программа обращается к модели, что бы определить подходящее время для повторной попытки). Он будет ждать наилучшего момента, чтобы повторить WinSock функцию.

Но тут может возникнуть вполне справедливый вопрос: если данная модель блокирует, то почему мы используем ее для неблокирующих socket’ов? Дело в том, что этот способ может «ждать» при многократных событиях. Ниже приведен прототип функции select:

select (nfds:DWORD, readfds:DWORD, writefds:DWORD, exceptfds:DWORD, timeout:DWORD)

Select определяет статус одного или нескольких socket’ов, предоставляя синхронизацию ввода/вывода, если это необходимо. Первый параметр игнорируется, последний параметр используется для определения оптимального времени «ожидания» функции. Остальные параметры определяют набор socket’ов: readfds – набор socket’ов, которые будут проверены на возможность чтения. writefds - набор socket’ов, которые будут проверены на возможность записи. exceptfds - набор socket’ов, которые будут проверены на наличие ошибок. «Возможность чтения» значит, что данные прибыли на socket, и, что само чтение после select’а аналогично получению данных. «Возможность записи» значит, что сейчас подходящее время для передачи данных, т.к. получатель, возможно, готов принять их. Exceptfds используется, чтобы «словить» ошибки из неблокирующих соединений.

WSAASyncSelect

Большинство оконных программ используют специальные диалоговые окна, что бы получить информацию от пользователя или наоборот. WinSock обеспечивает способ взаимодействия уведомлений о сетевых событиях с обработкой сообщений Windows. Функция WSAAsyncSelect позволяет зарегистрировать уведомление для определенного сетевого события в виде привычного сообщения Windows.

WSAAsyncSelect (s:DWORD, hWnd:DWORD, wMsg:DWORD, lEvent:DWORD)

Эта функция требует специального сообщения (wMsg), которое выбирает пользователь. А оконная процедура должна обработать это самое сообщение. lEvent является битовой маской, которая определяет событие, о котором будет сообщено. Рисунок для данной модели можно сделать таким:

Допустим, что первое сообщение хочет отправить какие-то данные socket’у, используя send. Так как socket неблокирующий, функция будет завершена мгновенно. Вызов функции может завершиться успешно, но тут этого не происходит. Предполагая, что WSAAsyncSelect была настроена таким образом, что сообщит нам о событии FD_WRITE, в конечном итоге мы получим сообщение от WinSock, говорящее нам о том, что данное событие произошло. В данном случае это событие FD_WRITE, которое означает что-то типа «Я готово, попробуй переслать свои данные». Таким образом, в обработчике сообщения программа пытается переслать данные, и эта попытка завершается успехом.

Беседа между программой и WinSock подобна модели select, различие лишь в методе уведомления: оконное сообщение вместо синхронного вызова select’а. В то время как select блокирует основной процесс, ожидая пока произойдет событие, программа, использующая WSAAsyncSelect, может продолжить обработку сообщений Windows до тех пор, пока не происходит никаких событий:

Программа регистрируется для уведомления о сетевых событиях через оконные сообщения Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа обрабатывает некоторое сообщение Программа обрабатывает другое сообщение Программа получает уведомляющее сообщение от WinSock Программа: «Отправь-ка эти данные» WinSock: «Сделано! »

WSAAsyncSelect обеспечивает более «Windows’овский» способ уведомления и он довольно прост в использовании. Для серверов с низкой пропускной способностью (меньше 1000 соединений) этот способ вполне хорош. Недостатком является то, что оконные сообщения, сами по себе, не очень быстрые, а так же в том, что для использования этой модели требуются окна (т.е. программа должна быть GUI).

WSAEventSelect

Примечание: под «объектом события» далее будет пониматься какое-то определенное сетевое событие. Дело в том, что тут событие рассматривается, как класс =). WSAEventSelect можно назвать родственником WSAAsyncSelect, который работает очень похожим способом, но вместо оконных сообщений использует объекты событий. В этом есть определенные преимущества, одним из которых является эффективность (объекты событий работают быстрее оконных сообщений). Графическая интерпретация этой модели выглядит немного сложнее, чем предыдущей, но на самом деле это не так:

Программа регистрируется для уведомления о сетевых событиях через объекты событий Программа: «Отправь-ка эти данные» WinSock: «Я не могу сделать это сейчас» Программа ждет события, чтобы сигнализировать о нем Программа: «Отправь-ка эти данные» WinSock: «Сделано! »

Трудно нарисовать изображение для этой функции, так как объекты событий - очень мощный механизм, который может использоваться разными способами. Я выбрал здесь простой пример использования. Из рисунка и диалога суть данной модели, на мой взгляд, более чем понятна. Поначалу эта модель похожа на блокирующую: Вы ждете событие, о котором Вам будет сообщено. Это верно, но в тоже самое время Вы можете создать свой объект события. Все объекты события являются частью WinAPI, которую использует WinSock. В WinSock есть некоторые функции для создания объектов, но фактически это API функции в WinSock упаковке. Все, что WinSock делает в этой модели, это сигнализирует объект события, когда это событие должно произойти. Функция, с помощью которой регистрируется сетевое событие WSAEventSelect:

WSAEventSelect (s:DWORD, hEventObject:DWORD, lNetworkEvents:DWORD)

WSAAsyncSelect отправит Вам сообщение о произошедшем сетевом событии (FD_READ, FD_WRITE, и т.д.) В отличие от WSAAsyncSelect, у WSAEventSelect есть только один способ уведомления: сигнализирование объекта событий. Это позволяет использовать данную модель как в GUI приложениях, так и в консольных. Какие события произошли можно узнать с помощью WSAEnumNetworkEvents.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]