Есть ли способ связать дескриптор файла с пользовательскими данными? - PullRequest
5 голосов
/ 18 ноября 2011

Я пишу клиент-серверное приложение, и оно использует функцию POSIX poll для обеспечения параллельной обработки клиента. Клиенты также имеют данные о состоянии и другие связанные данные, которые хранятся в структуре клиента.

Моя непосредственная проблема заключается в том, что когда я получаю подсказку от poll, чтобы выполнить ввод-вывод для дескриптора файла сокета, который связан с клиентом (концептуально), я должен фактически сопоставить дескриптор файла с соответствующими данными клиента состав. В настоящее время я выполняю поиск O(n_clients) (моя структура данных клиента хранит дескриптор), но мне было интересно, существует ли лучшая альтернатива?

Ответы [ 4 ]

4 голосов
/ 18 ноября 2011

Нет. Если бы оно было, оно должно было бы отслеживаться ядром, и поиск этих данных, следовательно, включал бы системный вызов. Стоимость системного вызова на порядок дороже, чем поиск O (n) в пространстве пользователя.

С сколькими клиентами вы общаетесь одновременно? Если это не порядка сотен и более, стоимость поиска будет минимальной по сравнению с затратами на любые операции ввода-вывода.

Вместо использования поиска O (n), вы также можете просто использовать массив, проиндексированный дескриптором файла, при условии, что у вас не будет открыто более определенного количества дескрипторов одновременно. Например:

#define MY_MAX_FD 1024  // Tune this to your needs
void *per_fd_data[MY_MAX_FD];

void *get_per_fd_data(int fd)
{
    assert(fd >= 0);
    if(fd < MY_MAX_FD)
        return per_fd_data[fd];
    else
    {
        // Look up fd in a dynamic associative array (left as an exercise to the
        // reader)
    }
}
2 голосов
/ 18 ноября 2011

Самый дешевый - просто создать массив структур соединений фиксированного размера, с {state, * context, ..., возможно, функциями обратного вызова} для каждой записи, , проиндексированными с помощью fd (= O (1)).Память дешева, и вы можете позволить себе несколько сотен или тысяч дескрипторов файлов и записей в таблицах.

РЕДАКТИРОВАТЬ: вам не нужно , чтобы сделать ее фиксированного размера.Если ваша структура опроса или fdset исправлена: сделайте это исправленным;в противном случае используйте getdtablesize () или getrlimit (), чтобы получить количество записей для выделения.

1 голос
/ 23 ноября 2016

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

Дело в том, что если мы предполагаем систему, совместимую с POSIX, http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_14,, то это указывает следующее (выделение мое):

Все функции, открывающие один или несколько файловых дескрипторов, должны, если не указано иное, атомарно назначать дескриптор файла с наименьшим номером (то есть, который еще не открыт в вызывающем процессе) на момент каждого выделения , Если одна функция выделяет два файловых дескриптора (например, pipe() или socketpair()), выделения могут быть независимыми, и поэтому приложения не должны ожидать, что они будут иметь смежные значения или зависеть от того, какое из них имеет более высокое значение.

Это позволяет программе просто зарезервировать массив до количества дескрипторов, которые она хочет поддерживать, при этом открытый дескриптор может быть просто использован как подстрочный индекс массива для ссылки на что-то вроде данных, связанных с подключением клиента. По сути, дескриптор открытого файла в таких системах может быть непосредственно использован в качестве индекса в таблице, которая реализована в виде массива. В конце концов, номера файловых дескрипторов будут не только расти вверх по сравнению с наименьшими доступными значениями, но также, похоже, будут использоваться повторно - если вы закроете дескриптор 10, пока у вас все еще открыты дескрипторы 11 и более, при следующем открытии дескриптора, POSIX- совместимая система откроет описание с индексом 10. Это также делает очень простым повторное использование строк в вашей индексированной таблице fd.

1 голос
/ 18 ноября 2011

Если вы используете poll() или select() / pselect(), то вы должны хранить данные самостоятельно, например, в хеш-таблице или массиве, как уже упоминали другие. Это самое портативное решение. У некоторых из альтернативных интерфейсов есть способы связать ваши собственные пользовательские данные. Например, используя асинхронный ввод / вывод (например, aio_read()), вы можете указать пользовательское значение sigev_value, которое можно передать обработчику сигнала или поток по завершении асинхронного запроса. Интерфейс Linux epoll также позволяет указывать пользовательские данные для каждого дескриптора файла в наборе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...