#c #c #linux #sockets
#c #c #linux #сокеты
Вопрос:
Я понимаю, что ничто не мешает linux присваивать дескрипторам любые случайные числа в диапазоне 0 … 2 ^ 32 при создании нового сокета. Но какова реальность? В моем приложении (веб-сервере) мне нужна структура сопоставления, которая отображает дескриптор в «структуру соединений». Я понимаю, что какое-то RB-дерево (int -> connection_ptr *) будет работать, но линейный массив указателей connection_ptr (где каждый указатель помещается в offset (index) = значение дескриптора) будет немного быстрее.
Комментарии:
1. Вы можете использовать хэшированный контейнер типа
std::unordered_map
(возможно, с пользовательским хэшером), чтобы получить как экономию места, так и очень быстрый доступ.2. Ничего не гарантируется
3. Я знаю, что вы спрашивали о Linux, но дескрипторы сокетов — это указатели в Windows, а не целые числа, поэтому они определенно не являются плотными в пространстве, поэтому любое решение, предполагающее, что они есть, не будет переноситься.
4. @EJP: Это зависит от того, какую реализацию стандартной библиотеки вы используете, но невозможно
select
предоставить, если они не являются целыми числами.
Ответ №1:
Файловые дескрипторы всегда назначаются с наименьшего доступного номера. Это гарантируется POSIX.
Комментарии:
1. Это для всего процесса или для всего компьютера? То есть, если у меня есть несколько других приложений, работающих и создающих / уничтожающих сокеты, я ожидал бы иметь (потенциально большие) пробелы с точки зрения одного приложения.
2. @MatthieuM. Для всего процесса. Файловые дескрипторы не имеют никакого значения вне процесса, который их создал.
3. Было бы здорово, если бы Windows-парень мог взвесить и сказать нам, если там то же самое.
4. @midor: насколько я понимаю, ответ отрицательный для функций, подобных псевдофайловым дескрипторам, предоставляемых в MSVCRT, но, конечно, да, если вы используете слой POSIX в Windows, такой как Cygwin, Interix и т. Д.
Ответ №2:
Даже если бы это было реализовано таким образом, если вы заботитесь о переносимости и надежности, вы не можете полагаться на это.
Чтобы получить почти постоянную сложность доступа, вы можете использовать хэшированный контейнер, например std:unordered_map
. Вы даже можете написать пользовательский хэшер, чтобы хранилище было оптимизировано для распределения номеров файловых дескрипторов.
struct SocketHasher {
size_t operator()(uint32_t key) {
return key amp; 0xFFFF;
}
}
std::unordered_map<uint32_t, connection_ptr, SocketHasher> connectionPool;
Комментарии:
1. Зачем мне нужен пользовательский хэшер?
2. Вы можете использовать его для лучшего распределения сокетов между сегментами карты, если вы знаете, как генерируются сокеты #. Однако эта часть полностью необязательна, и я предполагаю, что код будет хорошо работать и без нее.
3.Этот ответ неверен. Файловые дескрипторы определены таким образом, что они назначаются минимально доступным способом. Они не являются абстрактными дескрипторами, и вам не нужно обращаться с ними как с таковыми. (Примечание: контракт с открытым интерфейсом
select
требует, чтобы вы выполняли числовые сравнения (операция max) для файловых дескрипторов, и не работает, если все дескрипторы не находятся в фиксированном диапазоне от 0 доFD_SETSIZE-1
).