Ядро Linux 101: fd, системный вызов, сокет

Linux

Оригинальный адрес видео:Woohoo.YouTube.com/watch?V=F групповая покупка…

Обзор содержания этой статьи:

  • файловый дескриптор
  • Основы операционной системы
  • Файловые дескрипторы и процессы
  • Сетевые и розетки

файловый дескриптор

Я полагаю, вы знакомы с «В Unix все является файлом», например/devсодержание,/procКаталог и т. д., вы можете получить почти все данные, которые может получить система, манипулируя файлами. Для взаимодействия с файлами необходимо использовать файловые дескрипторы (файловые дескрипторы, сокращенно fd, — это число, уникальное внутри процесса).

С файлами вы можете делать эти вещи.

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

Существует несколько системных стандартных файловых дескрипторов:

  • 0: стандартный ввод, соответствующий Pythonsys.stdin
  • 1: Стандартный выход, соответствующийsys.stdout
  • 2: Стандартный вывод ошибок, соответствующийsys.stderr

Затем мы закрепим его несколькими примерами:

with open('example.txt') as f:
    print(f.read())

Вышеприведенная программа использует два fd, один из которых создается функцией открытия, а другой является fd стандартного вывода, который равен 1 при печати.

Вы также можете изменить права доступа к файлам на основе fd:

with open('example.txt') as f:
    stat = os.stat(f.fileno())
    os.chmod(f.fileno(), 0o640)

Есть даже контроль над оборудованием: приведенный ниже код можно использовать для извлечения компакт-диска.

Основы операционной системы

в темное средневековье. . . Прикладная программа может напрямую управлять оборудованием, а это значит, что если программа выйдет из строя, она выведет из строя всю систему, и тогда компьютер необходимо будет перезагрузить.

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

syscall

Каждый системный вызов будет передаваться из пользовательского пространства в пространство ядра, а затем возвращаться обратно в пользовательское пространство после запуска. Это означает, что требуется переключение контекста, поэтому скорость относительно низкая (количество необходимых тактов составляет порядка сотен).

Вернемся к предыдущему примеру:

# read.py
with open('example.txt') as f:
    print(f.read())

Существует инструмент, чтобы узнать, вызывает ли программа системный вызов:

$ strace ./read.py

открыть таблицу файлов и таблицу fd

Таблица открытых файлов является глобальной, здесь находятся все файлы, открытые процессом. У каждого процесса есть своя таблица fd, которая фактически указывает на таблицу открытых файлов:

Тот же процесс открывает один и тот же файл во второй раз, а fd другой.

Содержимое таблицы fd очень простое, а фактические подробные данные хранятся в таблице открытых файлов.

fork()

fork создает дочерний процесс, дочерний процесс наследует fd родительского процесса, и в то же времяcopy opn writeНа самом деле то, как основана память родительского процесса, можно рассматривать как то же самое содержимое, что и у родительского процесса. Наследование fd означает:

pid = os.fork()После этого дочерний процесс наследует файловый дескриптор родителя:f, они указывают на один и тот же файл в таблице открытых файлов, что означает, что их смещения одинаковы:

exec()

Замените память текущей программы, fd также будет унаследован, если не установленоcloexec. Существуют определенные проблемы в дочернем процессе, наследующем fd родительского процесса, что фактически эквивалентно утечке fd родительского процесса дочернему процессу, что принесет определенные риски безопасности. Так кто-то нарисовалпредложение pwp446, который предоставляет возможность закрыть родительский процесс fds:subprocessмодуль имеетclose_fdsпараметр, установленный наTrueозначает вызовexec, Кроме0,1,2Все fds, кроме трех, закрыты. Подробности можно узнатьpep446оригинальный текст иОфициальная документация подпроцесса.

Сеть и сокеты

Для сетевого взаимодействия требуется пара сетевых сокетов, один из которых работает на сервере, а другой — на клиенте. Процесс сокета на стороне сервера обычно привязан к определенному порту, например 80, 3306, 5432 и т. д. Он всегда будет прослушивать этот порт и запускать соответствующую логику после прослушивания запроса. Наконец, результат будет возвращен клиенту. Сокет клиента обычно временно привязывается к высокоуровневому порту.После завершения запроса (то есть завершения процесса) список будет аннулирован и драгоценные ресурсы порта будут освобождены.

в Питонеsocketмодуль, в основном нужно указать два параметра: выбрать IPV4 или IPV6, использовать UDP или TCP? Простой пример сервера:

пример клиента:

unix sockets

Сокеты Unix и сетевые сокеты на самом деле похожи, за исключением того, что они могут разрешать взаимодействие только процессам на одном компьютере. Одна сторона сокета домена UNIX знает, что другой процесс находится на машине, поэтому такие операции, как меры проверки и операции маршрутизации, не требуются, поэтому он относительно быстрее и легче.

В Python это используется так:bindа такжеconnectтеперь не IP-адрес и номер порта, а файл.Поскольку это файл, вы можете установить права на чтение и запись!Например, вы можете запретить пользователям определенной группы читать данные из этого сокета.

Если вы действительно любите компьютерные науки, как и я, и хотите изучать лежащую в их основе логику, добро пожаловать в мой публичный аккаунт WeChat: