Почему дескрипторы сокетов в Windows получают такие значения?

В любом случае, не уверен, что это правильное место для вопроса.
Я пишу простой чат на С++, где клиент получает значение сокета в качестве псевдонима для начала.
В linux сокеты — это просто файловые дескрипторы, и они получают свои 3, 4, 5... следующие за stdin, stdout, stderr.
Но я заметил, что в Win первый клиентский сокет всегда получает значение 192, а остальные отличаются на 20 (почти всегда).
g
Итак, вот мой вопрос, почему сокеты получают такие значения на платформе win (у меня win7 x64)? Небольшое гугление не помогло.
Заранее спасибо :D


person Aenry    schedule 31.07.2014    source источник
comment
Большинство дескрипторов в Windows представляют собой искаженные указатели, а не маленькие целые числа, как в Unix.   -  person user207421    schedule 01.08.2014
comment
Это деталь реализации - socket() может возвращать любые значения, которые его разработчики заботятся о том, чтобы он возвращал (конечно, до тех пор, пока возвращаемые идентификаторы сокетов неотрицательны и уникальны по отношению к другим существующим сокетам в процессе). Тем не менее, было бы интересно узнать, что именно Windows делает за кулисами.   -  person Jeremy Friesner    schedule 01.08.2014


Ответы (2)


В файловых дескрипторах POSIX используются целочисленные значения, и требуется, чтобы open возвращало значение, "которое является наименьшим дескриптор файла в данный момент не открыт для этого процесса». Кажется, это правило на самом деле не применяется к socket, но я не знаю ни одной системы Unix, которая также не применяет это правило к ней.

Однако Windows не использует сокеты POSIX. Он использует сокеты Windows, которые можно свободно определять способом, несовместимым с POSIX или исходной реализацией BSD. На самом деле существует множество несовместимостей с сокетами Windows. Наличие больших, чем вы ожидаете, значений сокетов является относительно незначительной несовместимостью в этих вещах.

В Windows Sockets 2 все "файловые дескрипторы" сокетов на самом деле являются дескрипторами Windows. Это означает, что их можно привести к HANDLE и использовать во многих функциях Windows API, которые принимают дескрипторы в качестве аргументов. Это также означает, что они используют одно и то же пространство значений, как и множество различных типов объектов, поддерживаемых Windows. Такие вещи, как файлы, потоки, ключи реестра, семафоры и так далее и тому подобное. Windows выделяет много их за кулисами для процесса, сама Winsock DLL использует изрядное количество из них, поэтому к тому времени, когда вы выделяете свой первый сокет, ваш процесс уже выделил значительное количество других дескрипторов.

Если вы используете Проводник процессов для просмотра запущенных процессов и включения параметра Показать дескрипторы без имени и Mappings, вы увидите, что даже самые простые процессы имеют довольно много открытых дескрипторов. Если вы включите столбец Handle и используете его для сортировки списка, вы также увидите, что наименьшее значение дескриптора равно 4 и что все они кратны 4. Большинство, если не все кратные из 4 будет выделено от 4 до самого высокого числа в списке.

Хотя он не объясняет, почему именно, Раймонд Чен в своем блоге Old New Thing на Почему дескрипторы ядра всегда кратны четырем? говорит, что число дескрипторов, кратное 4, гарантировано:

Не очень хорошо известно, что нижние два бита HANDLE ядра всегда равны нулю; другими словами, их числовое значение всегда кратно 4. Обратите внимание, что это относится только к дескрипторам ядра; он не применяется к псевдодескрипторам или к любому другому типу дескрипторов (USER >дескрипторы, дескрипторы GDI, мультимедийные дескрипторы...) Дескрипторы ядра — это то, что вы можете передать функции >CloseHandle.

Доступность двух нижних бит скрыта в заголовочном файле ntdef.h: // // Low order two bits of a handle are ignored by the system and available // for use by application code as tag bits. The remaining bits are opaque // and used to store a serial number and table index. //

В блоге Марка Руссиновича, посвященном Раздвигая границы Windows: дескрипторы, обсуждаются некоторые внутренности того, как дескрипторы реализованы в Windows. К сожалению, он не описывает, как на самом деле распределяются значения дескрипторов, но я думаю, что могу предположить некоторые детали. Запись в блоге описывает «трехуровневую схему». Дескрипторы используются в качестве индекса в таблице дескрипторов для каждого процесса, которая содержит указатели на таблицу записей дескрипторов для каждого процесса, которая, в свою очередь, содержит указатель на объект ядра для дескриптора. Windows увеличивает эти таблицы по мере необходимости и, вероятно, попытается сэкономить память, повторно используя дескрипторы после их закрытия.

Также, вероятно, не случайно, что список дескрипторов в Process Explorer имеет несколько пробелов. Поскольку процессы открывают и закрывают дескрипторы все время (часто это делается за кулисами какой-либо системной DLL), если бы Windows не активно повторно использовала закрытые дескрипторы, то список был бы намного более разреженным. Но использует ли Windows сначала самый низкий дескриптор?

Тестирование показывает, что это не так. Я написал программу, которая создает три ручки, закрывает первую, третью и вторую в указанном порядке и повторяет все это в цикле. Если бы Windows следовала правилам POSIX, то каждая итерация цикла создавала бы одни и те же значения дескрипторов в том же порядке, от меньшего к большему. Но вместо этого произошло то, что он создал те же значения дескрипторов в порядке, обратном их закрытию. Это говорит о том, что Windows, вероятно, повторно использует дескрипторы в порядке последних закрытых. Я предполагаю, что он реализует это, сохраняя связанный список нераспределенных дескрипторов в таблице дескрипторов.

Так почему же значения ваших сокетов начинаются со 192? Вероятно, потому, что на тот момент ваш процесс уже имел 47 открытых дескрипторов. Почему ваши сокеты отличаются на 20? Вероятно, потому что вы создаете 4 других дескриптора между созданием каждого сокета. Сам Winsock может создавать несколько дескрипторов за кулисами каждый раз, когда вы создаете сокет.

person Ross Ridge    schedule 01.08.2014

Больше информации о Winsock, которую вы когда-либо хотели: (Это означает, что вы должны прочитать и усвоить все это ;-)

http://www.tenouk.com/Winsock/Winsock2story.html

Джереми прав, идентификатор может быть HANDLE файла, HANDLE окна или просто неиспользуемым значением int. Я видел то, что кажется искаженными указателями при выполнении портов завершения ввода-вывода, поэтому на самом деле это может варьироваться в зависимости от того, какую часть сети Windows вы используете. (Винсок, Винсок2 и т. д.)

person Caladain    schedule 01.08.2014