Простой пример использования функции select
Теперь применим все сказанное на практике. Откройте пример TCPServer из разд. 4.7.1 и после создания сокета добавьте следующий код:
ULONG ulBlock; ulBlock = 1; if (ioctlsocket(sServerListen, FIONBIO, ulBlock) == SOCKET_ERROR) { return 0; }
Таким образом сокет переводится в асинхронный режим. Теперь попробуйте запустить пример. Сначала вы должны увидеть два сообщения "Bind OK" и "Listen OK", после чего программа вернет ошибку "Accept filed". В асинхронном режиме функция accept не блокирует работу программы, а значит, не ожидает соединения. В этом случае, если в очереди нет ожидающих подключения клиентов, то функция вернет ошибку WSAEWOULDBLOCK.
Чтобы избавиться от этого недостатка, нужно подкорректировать цикл ожидания соединения (бесконечный цикл while, который идет после вызова функции listen). Для асинхронного варианта он должен выглядеть, как в листинге 4.18.
Листинг 4.18. Цикл ожидания соединения |
while (1) { FD_ZERO(ReadSet); FD_SET(sServerListen, ReadSet);
if ((ReadySock = select(0, ReadSet, NULL, NULL, NULL)) == SOCKET_ERROR) { MessageBox(0, "Select filed", "Error", 0); }
if (FD_ISSET(sServerListen, ReadSet)) { iSize = sizeof(clientaddr); sClient = accept(sServerListen, (struct sockaddr *)clientaddr, iSize); if (sClient == INVALID_SOCKET) { MessageBox(0, "Accept filed", "Error", 0); break; }
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sClient, 0, dwThreadId); if (hThread == NULL) { MessageBox(0, "Create thread filed", "Error", 0); break; } CloseHandle(hThread); } }
Перед циклом добавлены две переменные: ReadSet типа FD_SET для хранения набора сокетов и ReadySock типа int для хранения количества готовых к использованию сокетов. На данный момент у нас только один сокет, поэтому эту переменную пока использовать не будем.
В самом начале цикла обнуляется набор с помощью функции FD_ZERO и добавляется созданный сокет, который ожидает подключения. После этого вызывается функция select. Для нее указан только второй параметр, а все остальные значения — нулевые. Если указан второй параметр, то функция ожидает возможности чтения для сокетов из набора. Параметр "время ожидания" тоже установлен в ноль, что соответствует бесконечному ожиданию.