Блокирующие процедуры Windows Sockets 1.1 и EINPROGRESS
Одной из основных проблем при переносе приложений из среды Berkeley Sockets в среду Windows является блокировка; то есть вызов функции, которая не возвращается до завершения связанной операции. Проблема возникает, когда операция занимает произвольно много времени: примером является функция recv , которая может блокироваться, пока данные не будут получены из одноранговой системы. Поведение по умолчанию в модели Berkeley Sockets заключается в том, что сокет работает в режиме блокировки, если программист явно не запрашивает, чтобы операции рассматривались как неблокирующие. Среды Windows Sockets 1.1 не могли предполагать упреждающую планирование. Поэтому настоятельно рекомендуется, чтобы программисты использовали неблокировку (асинхронные) операции, если это вообще возможно с Windows Sockets 1.1. Поскольку это не всегда было возможно, были предоставлены средства псевдоблокировки, описанные ниже.
Примечание
Windows Sockets 2 работает только в 32-разрядных операционных системах с вытеснениями, где взаимоблокировки не являются проблемой. Методы программирования, рекомендуемые для сокетов Windows 1.1, не являются обязательными в Windows Sockets 2.
Даже в блокирующем сокете некоторые функции, например bind, getockopt и getpeername , выполняются немедленно. Для этих функций нет никакой разницы между блокирующей и неблокирующей операцией. Другие операции, такие как recv, могут завершиться немедленно или занять произвольное время в зависимости от различных условий транспорта. При применении к блокирующем сокету эти операции называются блокирующими операциями. Следующие функции могут блокировать:
При использовании 16-разрядных сокетов Windows 1.1 операция блокировки, которая не может быть завершена немедленно, обрабатывается псевдоблокировкой следующим образом.
Поставщик услуг инициирует операцию, а затем входит в цикл, в котором отправляет все сообщения Windows (при необходимости передавая процессор в другой поток), а затем проверяет завершение функции Windows Sockets. Если функция завершена или был вызван WSACancelBlockingCall , блокирующая функция завершается с соответствующим результатом.
Поставщик услуг должен разрешить установку функции перехватчика блокировки, которая не обрабатывает сообщения, чтобы избежать возможности повторного входа сообщений, пока операция блокировки не выполняется. Простейшая такая блокирующая функция-перехватчик будет возвращать значение FALSE. Если библиотека DLL windows Sockets зависит от сообщений для внутренней операции, она может выполнить PeekMessage(hMyWnd...) перед выполнением перехватчика блокировки приложения, чтобы получать сообщения, не затрагивая остальную часть системы.
В 16-разрядной среде Windows Sockets 1.1 при получении сообщения Windows для процесса, для которого выполняется операция блокировки, существует риск того, что приложение попытается выполнить другой вызов сокетов Windows. Из-за трудностей безопасного управления этим условием Windows Sockets 1.1 не поддерживает такое поведение приложения. Приложению не разрешено выполнять несколько вызовов функции сокетов Windows. Для конкретной задачи допускается только один вызов невыполненных функций. Единственным исключением являются две функции, которые предоставляются для оказания помощи программисту в этой ситуации: WSAIsBlocking и WSACancelBlockingCall.
Функцию WSAIsBlocking можно вызвать в любое время, чтобы определить, выполняется ли блокирующий вызов Windows Sockets 1.1. Аналогичным образом, функцию WSACancelBlockingCall можно вызвать в любое время, чтобы отменить выполняющийся блокирующий вызов. Любая другая вложенная функция сокетов Windows завершается сбоем с ошибкой WSAEINPROGRESS.
Следует подчеркнуть, что это ограничение применяется как к блокирующим, так и к неблокирующим операциям. Для приложений Windows Sockets 2, которые согласовывают версию 2.0 или более позднюю во время вызова WSAStartup, нет ограничений на вложенности операций. Операции могут быть вложенными в редких случаях, например во время обратного вызова WSAAccept с условным принятием, или если поставщик услуг, в свою очередь, вызывает функцию Windows Sockets 2.
Хотя этого механизма достаточно для простых приложений, он не может поддерживать сложные требования к диспетчеризации сообщений для более сложных приложений (например, использующих модель MDI). Для таких приложений API сокетов Windows включает функцию WSASetBlockingHook, которая позволяет приложению указать специальную подпрограмму, которую можно вызвать вместо процедуры отправки сообщений по умолчанию, описанной в предыдущем обсуждении.
Поставщик сокетов Windows вызывает блокирующий перехватчик только в том случае, если выполняются все указанные ниже действия.
- Подпрограмма — это процедура, которая определена как возможность блокировки.
- Указанный сокет является блокирующим сокетом.
- Запрос не может быть выполнен немедленно.
Сокет по умолчанию заблокирован, но функция ioctlsocket с FIONBIO IOCTL или WSAAsyncSelect может установить для сокета неблокирующий режим.
Перехватчик блокировки никогда не вызывается, и приложению не нужно беспокоиться о проблемах повторной записи, которые могут возникнуть в перехватчике блокировки, если приложение следует следующим рекомендациям:
- Он использует только неблокировки сокетов.
- В нем используются процедуры WSAAsyncSelect и (или) WSAsyncGetXByY вместо процедур select и getXbyY .
Если приложение Windows Sockets 1.1 вызывает асинхронную или неблокизующую операцию, которая принимает в качестве аргумента указатель на объект памяти (например, буфер или глобальную переменную), приложение отвечает за обеспечение доступности объекта для сокетов Windows на протяжении всей операции. Приложение не должно вызывать какие-либо функции Windows, которые могут повлиять на сопоставление или адресную жизнеспособность используемой памяти.