Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы_сетевое.docx
Скачиваний:
58
Добавлен:
04.06.2015
Размер:
2 Мб
Скачать
☆
  1. 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.

  1. Модель перекрытого ввода-вывода

Перекрытый ввод/вывод является очень эффективным, особенно при хорошей реализации (позволяет обрабатывать очень много соединений). Это особенно касается сочетания перекрытого ввода/вывода с портами завершения. Как я говорил ранее, в большинстве случаев использование перекрытого ввода/вывода излишне, но я все равно постараюсь раскрыть эту тему, хотя бы, для общего развития.

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

Ценой этого эффективного подхода является трудная реализация. Если Вам не требуется действительно хорошая эффективность, то лучше воспользоваться ранее описанными моделями. Кроме того, операционные системы Windows 9x/ME не полностью поддерживают перекрытые модели ввода/вывода.

Как и модели с уведомлением о сетевых событиях, перекрытие модели так же могут быть реализованы по-разному. Они отличаются способом уведомления: блокирование, polling, процедуры завершения и порты завершения.

Перекрытый ввод/вывод: блокирование

Первая модель перекрытого ввода/вывода, о которой я расскажу, использует объект события для сигнализирования о завершении. Эта модель во многом похожа на WSAEventSelect, но отличием является то, что объект устанавливается в сигнализированное состояние при завершении WinSock операции, а не при наступлении какого-то сетевого события.

Программа: «Отправь-ка эти данные»

WinSock: «Окей, но я не могу отправить их прямо сейчас»

Программа ждет сигнала от объекта события, указывающего на то, что функция завершена

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

Перекрытый ввод/вывод: polling

Так же как и в ранее упомянутой модели polling, в этой модели так же можно запросить статус выполнения операции (хотя в ранее описанном polling’e мы не запрашивали статус выполнения, а просто получали данные о неудачном завершении функции. Но основной поток программы знал, когда функция завершилась неудачно, а когда наоборот). С помощью функции WSAGetOverlappedResult можно узнать статус выполняемой операции. Графическая интерпретация перекрытого polling’а очень похожа на интерпретацию обычного polling’а, за исключением того, что WinSock функция выполняется в то же время, что и опрос программы о выполнении функции.

Программа: «Отправь-ка эти данные»

WinSock: «Окей, но я не могу отправить их сейчас»

Программа: «Уже отправил?»

WinSock: «Нет»

Программа: «Уже отправил?»

WinSock: «Нет»

Программа: «Уже отправил?»

WinSock: «Нет»

Программа: «Уже отправил?»

WinSock: «Да! »

И тут я повторюсь: эта модель не очень хороша, так как она приводит процессор в панику. Поэтому я не рекомендую использовать эту модель.

Перекрытый ввод/вывод: процедуры завершения

Процедуры завершения – процедуры обратного вызова (т.е. вызываются в ответ на определенное действие. Далее я буду называть эти процедуры процедурами отзыва), которые вызываются при завершении операции. Тут вроде бы все просто, но есть одна хитрость: эти процедуры вызываются в контексте потока, который начал операцию. Что это значит? Представьте себе поток, который запросил перекрытую операцию записи. WinSock выполняет эту операцию, в то время как Ваш поток тоже выполняется. Таким образом у WinSock есть свой собственный поток для этой операции. Когда операция закончится, WinSock должен вызвать процедуру отзыва. Если это произойдет, то вызванная процедура будет выполняться в контексте потока WinSock. Это означает, что поток, вызвавший операцию записи, будет выполняться одновременно с процедурой вызова. Проблема состоит в том, что синхронизация с вызывающим потоком отсутствует, и он не знает, завершена ли операция (только если ему не сообщат об этом из параллельного потока).

Что бы избежать этого, WinSock удостоверяется в том, что процедура отзыва протекает в том же потоке, из которого происходил запрос. Осуществляется это с помощью APC (Asynchronous Procedure Call или Асинхронный Вызов Процедуры), механизма, встроенного в Windows. Это можно представить как «внедрение» процедуры в основной поток выполнения программы. Таким образом, поток сначала выполнит процедуру, а потом будет делать, то, что делал до ее «внедрения». Естественно, что система не может приказать потоку: «Прекрати делать все, что делал и обработай сначала эту процедуру».

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

Перекрытый ввод/вывод с процедурами завершения использует APC для уведомления о завершении операции.

Программа: «Отправь-ка эти данные»

WinSock: «Окей, но я не могу отправить их сейчас»

Программа входит в извещающее состояние ожидания

Функция завершилась

Состояние ожидания получает сигнал, о том, что функция завершена

Выполняется функция отзыва и управление переходит к программе

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