Вопрос

Мне интересно, есть ли простой способ потерять через 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.«Все еще действительны.

Вам понадобится некоторые специфические решения платформы:

Или вы могли бы использовать библиотеку событий, чтобы скрыть детали платформы для вас либев

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top