выбор Unix () вызов: как объединить fd_sets?

Я пишу приложение в C для Linux, который пользуется 2 отдельными сторонними библиотеками. Обе библиотеки являются асинхронными и используют выбор (). Они также обеспечивают API, который возвращает дескрипторы файлов, на которых они ожидают. Мое намерение состоит в том, чтобы передать их в мой собственный выбор () и затем возвратить управление назад тому, какой бы ни библиотека, когда их собственные значения fd установлены.

Я думаю, что у меня есть большая часть из него записанный, но я испытываю затруднения в точке, где выбор () параметры затронут: Обе библиотеки не дают отдельные дескрипторы файлов, но указатели на их чтение и пишут fd_sets. Я должен объединить возвращенный fd_sets из этих библиотек в один fd_set для чтения, один fd_set для записи, и т.д.

Какие-либо предложения о том, как я могу объединить 2 fd_sets в один получающийся fd_set?

Приложение Извините! Я должен был быть более ясным.. эти библиотеки только возвращают fd_sets... Я не знаю количество FDs в каждом наборе так, чтобы я мог сделать для цикла и установить каждый FD индивидуально.. существует ли простой способ определить данный просто fd_set?

5
задан nina 8 July 2010 в 05:49
поделиться

6 ответов

Вы можете настроить свой собственный fd_set , перебирая все возможные файловые дескрипторы, которые каждая библиотека могла бы открыть, и в каждом из их возвращаемых наборов, и установить свои соответственно. Это немного грубая сила, но интерфейс выбора, к сожалению, довольно примитивен. Например

fd_set *lib1_read_fds, *lib2_read_fds;
int fd;
fdset my_fd_set;
FD_CLR(&my_fd_set);
for (fd = 0; fd < FD_SETSIZE; fd++) {
    if (FD_ISSET(fd, lib1_read_fds) || FD_ISSET(fd, lib2_read_fds)) {
        FD_SET(fd, &my_fd_set);
    }
}
1
ответ дан 14 December 2019 в 04:29
поделиться

Код на C, который не зависит от реализации fd_set:

void Fdset_Add(fd_set *Out, fd_set const *In, int InNfds)
{
    for(i = 0; i < InNfds; i++)
    {
        if(i < InNfds && FD_ISSET(i, In))
            FD_SET(i, Out);
    }
}

int Fdset_Merge(fd_set *Out, fd_set const *In1, int NFds1, fd_set const *In2, int NFds2)
{
    FD_ZERO(Out);
    Fdset_Add(Out, In1, Nfds1);
    Fdset_Add(Out, In2, Nfds2);
    return Nfds1 > Nfds2 ? Nfds1 : Nfds2;
}

int Fdset_Filter(fd_set const *Result, int ResultNfds, fd_set *ToFilter, int NfdsToFilter)
{
    int i;
    int Retval;

    Retval = 0;
    for(i = 0; i < ResultNfds; i++)
    {
        if(i < NfdsToFilter && FD_ISSET(i, ToFilter))
        {
            if(! FD_ISSET(i, Result))
                FD_CLR(i, ToFilter);
            else
                Retval++;
        }
    }
    return Retval;
}

void Fdset_Split(fd_set const *Result, int ResultNfds, fd_set *In1, int Nfds1, int *Count1, fd_set *In2, int Nfds2, int *Count2)
{
     *Count1 = Fdset_Filter(Result, ResultNfds, In1, Nfds1);
     *Count2 = Fdset_Filter(Result, ResultNfds, In1, Nfds2);
}
5
ответ дан 14 December 2019 в 04:29
поделиться

Итерация через один набор и проверка каждого fd до FD_SETSIZE с помощью FD_ISSET(), и если он установлен, установить fd в другом наборе с помощью FD_SET()

1
ответ дан 14 December 2019 в 04:29
поделиться

Не полагаясь на внутреннюю реализацию fd_set, лучшее, что вы можете сделать, это простая пара циклов

fd_set combine_sets(fd_set* p_set1, int n1, fd_set* p_set2, int n2)
{
   fd_set combined;
   int i;

   FD_ZERO(combined);

   for (i = 0; i < n1; ++i) {
     if (FD_ISSET(i, p_set1)) {
       FD_SET(i, &combined);
     }
   }

   for (i = 0; i < n2; ++i) {
     if (FD_ISSET(i, p_set2)) {
       FD_SET(i, &combined);
     }
   }

   return combined;
}

Где параметры n являются наибольшим числом дескриптора потенциально в соответствующем множестве, плюс один (т.е. аргумент nfds, который вы бы передали select, если бы вы использовали только это множество).

Edit: Изменено, чтобы принимать указатели в качестве аргументов, так как это то, что вы сказали, что получаете из своих библиотек.

1
ответ дан 14 December 2019 в 04:29
поделиться

На самом деле fd_set - это битовая карта. Возможно, вы сможете объединить их с помощью бинарного или.

typedef long int __fd_mask;

typedef struct
{
    __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
} fd_set;
0
ответ дан 14 December 2019 в 04:29
поделиться

Я не думаю, что вы можете сделать это переносимо, однако если вы перепишите свой код для использования poll(), вы можете объединить используемые им наборы, поскольку они являются просто массивами переносимо structs

0
ответ дан 14 December 2019 в 04:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: