вызов unix select (): как объединить fd_sets? - PullRequest
5 голосов
/ 07 июля 2010

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

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

Любые предложения о том, как объединить 2 набора fd_sets в один результирующий набор fd_set?

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

Ответы [ 6 ]

5 голосов
/ 07 июля 2010
Код

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);
}
1 голос
/ 07 июля 2010

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

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 голос
/ 07 июля 2010

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

1 голос
/ 07 июля 2010

Не полагаясь на внутреннюю реализацию 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: Изменен, чтобы принимать указатели в качестве аргументов, так как этото, что вы сказали, вы получаете из своих библиотек.

0 голосов
/ 07 июля 2010

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

0 голосов
/ 07 июля 2010

fd_set на самом деле является растровым изображением. Может быть, вы можете объединить их с помощью двоичного или.

typedef long int __fd_mask;

typedef struct
{
    __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
} fd_set;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...