WSAAsyncSelect
WSADuplicateSocket
), и первая программа вызывает WSAAsyncSelect
со своим дескриптором, а затем вторая — со своим, то вызов WSAAsyncSelect
, сделанный во второй программе, отменит вызов, сделанный в первой.Для того, чтобы получать сообщения при готовности сокета как к чтению, так и к записи, нужно выполнить следующий код.
WSAAsyncSelect(S, Form1.Handle, WM_USER, FD_READ or FD_WRITE);
При необходимости с помощью or
Из сказанного следует, что нельзя связать с разными событиями одного и того же сокета разные сообщения (или отправлять сообщения разным окнам), т.к. при одном вызове WSAAsyncSelect
WSAAsyncSelect
переводит сокет в неблокирующий режим. Если необходимо использовать асинхронный сокет в блокирующем режиме, после вызова WSAAsyncSelect
требуется перевести его в этот режим вручную.Сообщение, которое связывается с асинхронным сокетом, может быть любым. Обычно его номер выбирают от WM_USER
При получении сообщения его параметр wParam
lParam
содержит произошедшее событие (одну из констант FD_XXX
), а старшее слово — код ошибки если она произошла. Для выделения кода события и кода ошибки из lParam
в библиотеке WinSock предусмотрены макросы WSAGETSELECTEVENT
и WSAGETSELECTERROR
соответственно. В модуле WinSock они заменены функциями WSAGetSelectEvent
и WSAGetSelectError
. Одно сообщение может информировать только об одном событии на сокете. Если произошло несколько событий, в очередь окна будет добавлено несколько сообщений.Сокет, созданный при вызове функции accept
accept
, будет асинхронным, и тот же набор его событий будет связан с тем же сообщением, что и у исходного сокета.Рассмотрим подробнее каждое из перечисленных событий.
Событие FD_READ
WSAAsyncSelect
, разрешающего такие события, в буфере сокета уже есть данные, то событие также возникает). Как только соответствующее сообщение помещается в очередь окна, дальнейшая генерация таких сообщений для этого сокета блокируется, т.е. получение новых данных не будет приводить к появлению новых сообщений (при этом сообщения, связанные с другими событиями этого сокета или с событием FD_READ
других сокетов, будут по-прежнему помещаться при необходимости в очередь окна). Генерация сообщений снова разрешается после того, как будет вызвана функция для чтения данных из буфера сокета (это может быть функция recv
, recvfrom
, WSARecv
или WSARecvFrom
, мы в дальнейшем будем говорить только о функции recv
, потому что остальные ведут себя в этом отношении аналогично).Если после вызова recv
FD_READ
, сообщение о котором помещается в очередь. Когда программа начинает обрабатывать это сообщение, она вызывает recv
и читает часть данных из буфера. Так как данные в буфере еще есть, снова генерируется сообщение о событии FD_READ
, которое ставится в конец очереди. Через некоторое время программа снова начинает обрабатывать это сообщение. Если и на этот раз данные будут прочитаны не полностью, в очередь снова будет добавлено такое же сообщение. И так будет продолжаться до тех пор, пока не будут прочитаны все полученные данные.