Давайте быстро рассмотрим файлы устройств: в Linux прикладные программы передают в ядро операции write и write с помощью файловых дескрипторов . Это прекрасно работает для файлов, и оказалось, что один и тот же API можно использовать для символьных устройств, которые генерируют и потребляют потоки символов, и для блочных устройств, которые читают и записывают блоки фиксированного размера по адресу произвольного доступа, просто притворяясь, что они также файлы.
Но был необходим способ настройки этих устройств (установка скорости передачи и т. Д.), И для этого был изобретен вызов ioctl . Он просто передает структуру данных, специфичную для устройства, и тип управления вводом / выводом, используемый ядром, и возвращает результаты в той же структуре данных, так что это очень универсальный расширяемый API, который можно использовать для многих целей. ,
Теперь, как вписываются сетевые операции? Типичное приложение сетевого сервера хочет привязать к некоторому сетевому адресу, прослушивать определенный порт (например, 80 для HTTP или 22 для ssh), и, если клиент подключается , он хочет отправлять данные и получать данные от этого клиента. И двойные операции для клиента.
Не очевидно, как это согласовать с файловыми операциями (хотя это можно сделать, см. Plan 9 ), поэтому дизайнеры UNIX изобрели новый API: сокеты . Вы можете найти подробную информацию в справочных страницах раздела 2 для socket
, bind
, listen
, connect
, send
и recv
. Обратите внимание, что, хотя он отличается от API ввода-вывода файлов, socket
вызов, тем не менее, также возвращает дескриптор файла. Есть множество уроков по использованию сокетов в сети, немного погуглите.
Пока это все чисто UNIX, никто не говорил о сетевых интерфейсах в то время, когда были изобретены сокеты. И поскольку этот API действительно старый, он определен для множества сетевых протоколов, помимо интернет-протокола (посмотрите на AF_*
константы), хотя в Linux поддерживаются только некоторые из них.
Но поскольку компьютеры начали получать несколько сетевых карт, для этого потребовалась некоторая абстракция. В Linux это сетевой интерфейс (NI). Он используется не только для аппаратного обеспечения, но также и для различных туннелей, конечных точек пользовательских приложений, которые представляют собой такие туннели, как OpenVPN и т. Д. Как было объяснено, API сокетов не основан на (специальных) файлах и не зависит от файловой системы. Точно так же сетевые интерфейсы также не отображаются в файловой системе. Однако NIs сделаны доступными в /proc
и /sys
файловой системы (а также другие сетевые переменные вручную ).
NI - это просто абстракция ядра конечной точки, в которую сетевые пакеты входят и выходят из ядра. Сокеты, с другой стороны, используются для обмена пакетами с приложениями. Нет необходимости использовать сокет для обработки пакета. Например, когда включена пересылка, пакет может входить в один NI и уходить в другой. В этом смысле сокеты и сетевые интерфейсы полностью независимы.
Но должен был быть способ настройки NI, точно так же, как вам нужен был способ настройки блочных и символьных устройств. А поскольку сокеты уже возвращали дескриптор файла, было несколько логично просто разрешить ioctl
дескриптор этого файла. Это интерфейс сетевого устройства, который вы связали.
Существует довольно много других злоупотреблений системными вызовами подобным образом, например, для фильтрации пакетов, захвата пакетов и т. Д.
Все это росло по частям, и во многих местах это не особенно логично. Если бы он был спроектирован сразу, можно было бы сделать более ортогональный API.