#ifdef WIN32
int iMode = 1;
ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode );
#else
fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK );
#endif
fd_set fd;
FD_ZERO( &fd );
FD_SET( m_Socket, &fd );
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
// check if the socket is connected
#ifdef WIN32
if( select( 1, NULL, &fd, NULL, &tv ) == SOCKET_ERROR )
#else
if( select( m_Socket + 1, NULL, &fd, NULL, &tv ) == SOCKET_ERROR )
#endif
{
m_HasError = true;
m_Error = GetLastError( );
return false;
}
if( FD_ISSET( m_Socket, &fd ) )
{
m_Connecting = false;
m_Connected = true;
return true;
}
Не пойму, что происходит с select
и FD_ISSET
? Кого и как select
оповещает о доступных данных? И зачем FD_ISSET
проверяет, есть ли сокет в наборе, ведь он же явно там есть, так как FD_SET
вызывался. Получается, что select
сразу возвращает управление, но при этом операционная система следит за тем, есть ли данные для сокета, и если нету, то удаляет сокет из набора, а если есть, то добавляет снова, поэтому и нужен FD_ISSET
?
Для начала нужно понять, что такое fd_set fd;
- это просто массив (почти, см. ниже) на 1024 элемента (в некоторых случаях там может быть другое число, закладываться на него не нужно).
typedef struct fd_set {
unsigned int count;
int fd[FD_SETSIZE];
} fd_set;
Индекс этого массива - это просто номер сокета (в той реализации, которую я нашел, сделано наоборот - значение это сокет, но это не меняет сути. Разные оси по-разному оптимизируют). Функция (макрос) FD_SET просто выставляет флажок в этом массиве. FD_ZERO просто снимает все флажки. FD_ISSET просто проверяет наличие флажка для заданного номера сокета.
А теперь главное. Что делает select. Он получает несколько таких наборов. То есть есть набор номеров сокетов и ожидаемые действия от них. Селект следит за данными сокетами, и если по ним происходят изменения, то он модифицирует массивы (не забываем, их там три). А потом просто возвращает количество модификаций.
И вот теперь с помощью FD_ISSET можно проверить, были ли изменения по данному сокету (проверять-то нужно в каждом массиве, так как разные массивы для разных действий).
Кого и как select оповещает о доступных данных?
Ваш код. Потому как Ваш код проверяет результат.
И зачем FD_ISSET проверяет, есть ли сокет в наборе, ведь он же явно там есть, так как FD_SET вызывался.
В том то и дело, что его там может и не быть (если по нему не было заданных изменений).
Получается, что select сразу возвращает управление, но при этом операционная система следит за тем, есть ли данные для сокета, и если нету, то удаляет сокет из набора, а если есть, то добавляет снова, поэтому и нужен FD_ISSET?
select не сразу возвращает управление. Он возвращает управление в трех случаях
После выхода с select'а набор уже может быть модифицирован.
Обновление
Есть две реализации fd_set. В той реализации, которую я нашел прям сейчас - fd_set просто добавляет в массив номер сокета (даже без проверки, что он там уже есть) и увеличивает счетчик сокетов в массиве.
В этой реализации он просто удаляет из массива те номера дескрипторов, которые не изменялись, и оставляет в массиве те номера, по которым были изменения.
FD_ISSET в этой реализации просто ищет, есть ли в массиве данный дескриптор.
Если тайм-ауты нулевые, то select просто проверит состояние сокетов и выставит правильно номера дескрипторов в массиве и сразу выйдет.
Обновление 2
Этих действий не много. Это есть данные для чтения, есть данные для записи, есть внеочередные данные (это особое, редко используется), сокет закрылся для записи, сокет закрылся для чтения (да, можно делать полузакрытый сокет).
и выставит правильно номера дескрипторов в массиве
select смотрит на номера сокетов, которые ему передали и следит за их изменениями. Когда изменения есть (или наступил тайм-аут), то он собирает список измененных сокетов и записывает их в массив (а сам массив перед этим почистит).
Я посмотрел детальнее. Реализация, где индексы - дескрипторы - это линуксовое. Где дескрипторы записываются в массив по значению - это виндовое. Кстати, по этой причине в виндовс медленный select. Но зато у него нет одной проблемы, которая есть в линуксе - если номер сокета больше 1023, то линуксовый select не будет работать (просто пишется за пределы массива). В виндовс формально сокеты не имеют номера (хотя его имеют, но это деталь реализации), и select будет работать с любыми сокетами, пока их общее количество не превысит максимума.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
На вход подается описание бинарного дереваНа листьях (висячих вершинах) этого дерева написаны целые числа (от -10^6 до 10^6)
Есть такая проблема: имеется иерархия классовВ производных появляются новые методы