Как повторить через fd_set
-
01-10-2019 - |
Вопрос
Мне интересно, есть ли простой способ потерять через fd_set? Причина, по которой я хочу сделать это, это не иметь петли через все подключенные сокеты, поскольку SELECT () изменяет эти FD_SET, чтобы включить только те, которые меня интересуют. Я также знаю, что используя реализацию типа, который не предназначен для непосредственного доступа, - это, как правило, является плохой идеей, поскольку она может варьироваться в различных системах. Однако мне нужен какой-то способ сделать это, и у меня нет идей. Итак, мой вопрос:
Как мне перейти через fd_set? Если это действительно плохая практика, есть ли другие способы решить мою «проблему», за исключением цикла через все подключенные сокеты?
Спасибо
Решение
Выберите Устанавливает бит, соответствующий дескриптору файла в наборе, так что вам нужно, не повторяйте все FDS, если вы заинтересованы всего в нескольких (и могут игнорировать другие), просто тестируйте только те файловые дескрипторы, для которых вы заинтересованы Отказ
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
if(FD_ISSET(fd0, &read_fds))
{
//do things
}
if(FD_ISSET(fd1, &read_fds))
{
//do more things
}
РЕДАКТИРОВАТЬ
Вот структура fd_set:
typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;
Где fd_count - это количество набора розеток (так, вы можете добавить оптимизацию, используя это), и fd_array - это битовый вектор (размер fd_setsize * sizeof (int) который зависит от машины). В моей машине это 64 * 64 = 4096.
Итак, ваш вопрос по сути: каков самый эффективный способ найти битные позиции 1S в немного векторе (размером около 4096 битов)?
Я хочу очистить одну вещь здесь:
«Заворачивание всех подключенных розетков» не означает, что вы на самом деле читаете / делаете вещи в соединение. Fd_isset () Проверяет только погодные данные. Если эффективность - ваша цель, то не так уж наиболее эффективно? Использование эвристики?
Пожалуйста, скажите нам, что не так с этим методом, и что вы пытаетесь достичь использования альтернативного метода.
Другие советы
Вы должны заполнить структуру FD_Set перед выбором выбора (), вы не можете пройти в оригинальном STD :: Набор розетков напрямую. Выберите () Затем изменяет соответственно FD_SET, удаляя любые розетки, которые не «устанавливаются», и возвращает, сколько остается розетки. Вы должны зацикливаться через полученную FD_Set, а не ваш STD :: Set. Нет необходимости звонить FD_isset (), потому что полученный FD_Set содержит только «установить» сокеты, которые готовы, например:
fd_set read_fds;
FD_ZERO(&read_fds);
int max_fd = 0;
read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i )
{
read_fds.fd_array[i] = connected_sockets[i];
if (read_fds.fd_array[i] > max_fd)
max_fd = read_fds.fd_array[i];
}
if (select(max_fd+1, &read_fds, NULL, NULL, NULL) > 0)
{
for( int i = 0; i < read_fds.fd_count; ++i )
do_socket_operation( read_fds.fd_array[i] );
}
Где FD_isset () входит в игру чаще, при использовании ошибок проверки с выбором (), например:
fd_set read_fds;
FD_ZERO(&read_fds);
fd_set error_fds;
FD_ZERO(&error_fds);
int max_fd = 0;
read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i )
{
read_fds.fd_array[i] = connected_sockets[i];
if (read_fds.fd_array[i] > max_fd)
max_fd = read_fds.fd_array[i];
}
error_fds.fd_count = read_fds.fd_count;
for( int i = 0; i < read_fds.fd_count; ++i )
{
error_fds.fd_array[i] = read_fds.fd_array[i];
}
if (select(max_fd+1, &read_fds, NULL, &error_fds, NULL) > 0)
{
for( int i = 0; i < read_fds.fd_count; ++i )
{
if( !FD_ISSET(read_fds.fd_array[i], &error_fds) )
do_socket_operation( read_fds.fd_array[i] );
}
for( int i = 0; i < error_fds.fd_count; ++i )
{
do_socket_error( error_fds.fd_array[i] );
}
}
Это довольно прямо вперед:
for( int fd = 0; fd < max_fd; fd++ )
if ( FD_ISSET(fd, &my_fd_set) )
do_socket_operation( fd );
Этот цикл является ограничением select()
интерфейс. Основные реализации fd_set
Обычно это набор битов, который, очевидно, означает, что в поисках сокета требуется сканирование над битами.
Именно в этом причина, что несколько альтернативных интерфейсов были созданы - к сожалению, все они являются всеми ОС. Например, Linux обеспечивает эполл, который возвращает список только дескрипторов файлов, которые активны. FreeBSD и Mac OS X Оба предоставляют kqueue., который достигает того же результата.
Смотрите этот раздел 7.2 БешеРуководство по сети - '7.2. Выберите () - синхронный мультиплексирование ввода / вывода «с помощью FD_isset.
Короче говоря, вы должны перейти через FD_Set, чтобы определить, готов ли файловый дескриптор для чтения / записи ...
Я не думаю, что вы пытаетесь сделать, это хорошая идея.
Во-первых, его система зависит от системы, но я верю, что вы уже знаете это.
Во-вторых, на внутреннем уровне эти наборы хранятся в виде массива целых чисел и FDS хранятся в виде установочных битов. Теперь в соответствии с страницами человека выбрать FD_SECSIZE 1024. Даже если вы хотите перейти за повторение и получить ваш заинтересованный FD, вы должны заинтересовать этот номер вместе с беспорядком битовой манипулирования. Поэтому, если вы не ждете больше, чем fd_setsize FD на выборе, который я не думаю, это возможно, это не хорошая идея.
О, подожди !! В любом случае это не хорошая идея.
Я не думаю, что вы можете сделать много, используя select()
Вызов эффективно. Информация на "Проблема C10K.«Все еще действительны.
Вам понадобится некоторые специфические решения платформы:
Или вы могли бы использовать библиотеку событий, чтобы скрыть детали платформы для вас либев