На многих устройствах основными операциями являются отправка байтов с компьютера на периферийное устройство или получение байтов с периферийного устройства на компьютере. Такие устройства похожи на трубы и хорошо работают как символьные устройства . Для операций, которые не читают и не записывают (например, управление потоком данных по последовательной линии), устройство предоставляет специальные команды, называемые ioctl .
Некоторые устройства очень похожи на обычные файлы: они состоят из конечного числа байтов, и то, что вы пишете в заданной позиции, позже может быть прочитано из той же позиции. Эти устройства называются блочными устройствами .
Сетевые интерфейсы более сложны: они читают и пишут не байты, а пакеты. Хотя все еще можно было бы использовать обычный интерфейс с read
и write
, это было бы неудобно: предположительно, каждый вызов write
отправлял бы пакет, и каждый вызов read
получал бы пакет (и если буфер слишком мал для пакета, чтобы уместиться, пакет будет потерян).
Сетевые интерфейсы могут существовать только в качестве устройств ioctl
. Фактически, это то, что делают некоторые варианты Unix, но не Linux. У этого подхода есть некоторое преимущество; например, в Linux сетевые интерфейсы могут использовать udev . Но преимущества ограничены, поэтому это не было сделано.
Большинство сетевых приложений не заботятся об отдельных сетевых интерфейсах, они работают на более высоком уровне. Например, веб-браузер хочет устанавливать TCP-соединения, а веб-сервер хочет прослушивать TCP-соединения. Для этой цели было бы полезно использовать устройства для сетевых протоколов высокого уровня, например
{ echo $'GET http://www.google.com/ HTTP/1.0\r';
echo $'Host: www.google.com\r';
echo $'\r' >&0; cat; } <>/dev/tcp/www.google.com/80
Фактически, ksh и bash предоставляют такой интерфейс для клиентов TCP и UDP. В целом, однако, сетевые приложения более сложны, чем приложения для доступа к файлам. Хотя большинство обменов данными осуществляется с помощью вызовов, аналогичных read
и write
, для установления соединения требуется больше информации, чем просто имя файла. Например, прослушивание TCP-соединений выполняется в два этапа: один из них выполняется, когда сервер начинает прослушивание, и один - при каждом подключении клиента. Такие дополнительные шаги плохо вписываются в файловый API, что является основной причиной, по которой сеть имеет свой собственный API.
Другой класс устройств, которые обычно не имеют записей в /dev
Linux (но есть в некоторых других вариантах Unix), это видеоадаптеры. В принципе, простые видеоадаптеры могут быть представлены как устройства кадрового буфера , которые могут быть блочными устройствами, состоящими из блоков, представляющих цвет каждого пикселя. Ускоренные видеоадаптеры могут быть представлены как символьные устройства, на которые приложения отправляют команды. Здесь недостатком интерфейса устройства является то, что он медленный: приложение отображения (на практике X-сервер) должно было бы выполнять вызовы ядра при каждом отображении чего-либо. Вместо этого происходит то, что X-сервер в основном пишет непосредственно в память видеоадаптера, потому что он быстрее.