Я пишу приложение в C для Linux, который пользуется 2 отдельными сторонними библиотеками. Обе библиотеки являются асинхронными и используют выбор (). Они также обеспечивают API, который возвращает дескрипторы файлов, на которых они ожидают. Мое намерение состоит в том, чтобы передать их в мой собственный выбор () и затем возвратить управление назад тому, какой бы ни библиотека, когда их собственные значения fd установлены.
Я думаю, что у меня есть большая часть из него записанный, но я испытываю затруднения в точке, где выбор () параметры затронут: Обе библиотеки не дают отдельные дескрипторы файлов, но указатели на их чтение и пишут fd_sets. Я должен объединить возвращенный fd_sets из этих библиотек в один fd_set для чтения, один fd_set для записи, и т.д.
Какие-либо предложения о том, как я могу объединить 2 fd_sets в один получающийся fd_set?
Приложение Извините! Я должен был быть более ясным.. эти библиотеки только возвращают fd_sets... Я не знаю количество FDs в каждом наборе так, чтобы я мог сделать для цикла и установить каждый FD индивидуально.. существует ли простой способ определить данный просто fd_set?
Вы можете настроить свой собственный 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);
}
}
Код на 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);
}
Итерация через один набор и проверка каждого fd до FD_SETSIZE с помощью FD_ISSET(), и если он установлен, установить fd в другом наборе с помощью FD_SET()
Не полагаясь на внутреннюю реализацию 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: Изменено, чтобы принимать указатели в качестве аргументов, так как это то, что вы сказали, что получаете из своих библиотек.
На самом деле fd_set - это битовая карта. Возможно, вы сможете объединить их с помощью бинарного или.
typedef long int __fd_mask;
typedef struct
{
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
} fd_set;
Я не думаю, что вы можете сделать это переносимо, однако если вы перепишите свой код для использования poll()
, вы можете объединить используемые им наборы, поскольку они являются просто массивами переносимо struct
s