D-Bus (сокращение от « Desktop Bus » [4] ) — это механизм промежуточного программного обеспечения, ориентированный на сообщения , который обеспечивает связь между несколькими процессами , одновременно работающими на одной машине. [5] [6] D-Bus был разработан в рамках проекта freedesktop.org , инициированного разработчиком GNOME Хэвоком Пеннингтоном с целью стандартизации сервисов, предоставляемых средами рабочего стола Linux , такими как GNOME и KDE . [7] [8] [ неработающая ссылка ]
Проект freedesktop.org также разработал бесплатную программную библиотеку с открытым исходным кодом под названием libdbus в качестве эталонной реализации спецификации. Эту библиотеку не следует путать с самой D-Bus, поскольку существуют и другие реализации спецификации D-Bus, такие как GDBus (GNOME), [9] QtDBus ( Qt /KDE), [10] dbus-java [11] и sd-bus (часть systemd ). [12]
D-Bus — это механизм межпроцессного взаимодействия (IPC), изначально разработанный для замены систем связи программных компонентов , используемых средами рабочего стола GNOME и KDE Linux ( CORBA и DCOP соответственно). [13] [14] Компоненты этих сред рабочего стола обычно распределены по множеству процессов, каждый из которых предоставляет лишь несколько — обычно одну — услуг . Эти службы могут использоваться обычными клиентскими приложениями или другими компонентами среды рабочего стола для выполнения своих задач. [15]
Из-за большого количества задействованных процессов — сложения процессов, предоставляющих услуги , и клиентов, получающих к ним доступ — установление индивидуального IPC между всеми ними становится неэффективным и довольно ненадежным подходом . Вместо этого D-Bus предоставляет абстракцию программной шины , которая собирает все сообщения между группой процессов по одному общему виртуальному каналу. [6] Процессы, подключенные к шине, не знают, как это реализовано внутри, но спецификация D-Bus гарантирует, что все процессы, подключенные к шине, могут взаимодействовать друг с другом через нее.
Среды рабочего стола Linux используют возможности D-Bus, создавая экземпляры нескольких шин, в частности: [16] [6] [17]
Процесс может подключаться к любому количеству шин при условии, что ему предоставлен к ним доступ. На практике это означает, что любой пользовательский процесс может подключаться к системной шине и к своей текущей сеансовой шине, но не к сеансовым шинам другого пользователя или даже к другой сеансовой шине, принадлежащей тому же пользователю. Последнее ограничение может измениться в будущем, если все пользовательские сессии объединить в одну пользовательскую шину. [18]
D-Bus предоставляет приложениям дополнительные или упрощает существующие функциональные возможности, включая обмен информацией, модульность и разделение привилегий . Например, информация о входящем голосовом вызове, полученном через Bluetooth или Skype , может распространяться и интерпретироваться любым работающим в данный момент музыкальным проигрывателем, который может реагировать отключением громкости или приостановкой воспроизведения до завершения вызова. [19]
D-Bus также можно использовать в качестве основы для интеграции различных компонентов пользовательского приложения. Например, офисный пакет может взаимодействовать через сеансовую шину для обмена данными между текстовым процессором и электронной таблицей .
Каждое подключение к шине идентифицируется в контексте D-Bus так называемым именем шины . [5] Имя шины состоит из двух или более строк букв, цифр, тире и подчеркиваний, разделенных точками. Пример допустимого имени шины: org.freedesktop.NetworkManager
. [6]
Когда процесс устанавливает соединение с шиной, шина присваивает этому соединению специальное имя шины, называемое уникальным именем соединения . [17] [6] Имена шин этого типа неизменяемы — гарантированно, что они не изменятся, пока существует соединение — и, что более важно, их нельзя использовать повторно в течение срока службы шины. [5] [17] [6] Это означает, что никакому другому соединению с этой шиной никогда не будет присвоено такое уникальное имя соединения, даже если тот же процесс закроет соединение с шиной и создаст новое. Уникальные имена соединений легко узнать, поскольку они начинаются с запрещенного в противном случае символа двоеточия. [17] [6] Пример уникального имени соединения :1.1553
(символы после двоеточия не имеют особого значения [17] ).
Процесс может запросить дополнительные имена шин для своего подключения [17] при условии, что любое запрошенное имя еще не используется другим подключением к шине. На языке D-Bus, когда соединению присваивается имя шины, говорят, что имя шины принадлежит соединению . [5] [17] В этом смысле имя шины не может принадлежать двум соединениям одновременно, но, в отличие от уникальных имен соединений, эти имена могут использоваться повторно, если они доступны: процесс может вернуть освобожденное имя шины — намеренно или нет — с помощью другого процесса. [5] [6]
Идея этих дополнительных имен шин, обычно называемых общеизвестными именами , заключается в том, чтобы предоставить возможность обращаться к службе с использованием заранее заданного имени шины. [17] [6] Например, служба, сообщающая текущее время и дату по системной шине, находится в процессе, соединению которого принадлежит имя шины org.freedesktop.timedate1 , независимо от того, какой это процесс.
Имена шин можно использовать как простой способ реализации одноэкземплярных приложений (вторые экземпляры обнаруживают, что имя шины уже занято). [17] Его также можно использовать для отслеживания жизненного цикла процесса обслуживания, поскольку шина отправляет уведомление, когда имя шины освобождается из-за завершения процесса. [17]
Из-за своей первоначальной концепции замены нескольких компонентно-ориентированных систем связи, D-Bus разделяет со своими предшественниками объектную модель, в которой выражается семантика связи между клиентами и службами. Термины, используемые в объектной модели D-Bus, имитируют термины, используемые в некоторых объектно-ориентированных языках программирования . Это не означает, что D-Bus каким-то образом ограничен ООП-языками — на самом деле наиболее используемая реализация ( libdbus ) написана на C , процедурном языке программирования .
В D-Bus процесс предлагает свои услуги, предоставляя объекты . Эти объекты имеют методы , которые можно вызывать, и сигналы , которые может излучать объект. [17] Методы и сигналы вместе называются членами объекта . [5] Любой клиент, подключенный к шине, может взаимодействовать с объектом, используя его методы, делая запросы или приказывая объекту выполнять действия. [17] Например, объект, представляющий службу времени, может быть запрошен клиентом с использованием метода, который возвращает текущую дату и время. Клиент также может прослушивать сигналы, которые излучает объект, когда его состояние изменяется из-за определенных событий, обычно связанных с базовой службой. Примером может служить ситуация, когда служба, управляющая аппаратными устройствами, такими как USB или сетевые драйверы, сигнализирует о событии «добавлено новое аппаратное устройство». Клиенты должны сообщить шине, что они заинтересованы в получении определенных сигналов от конкретного объекта, поскольку шина D-Bus передает сигналы только тем процессам, которые имеют к ним зарегистрированный интерес. [6]
Процесс, подключенный к шине D-Bus, может запросить экспорт любого количества объектов D-Bus. Каждый объект идентифицируется путем к объекту , строкой цифр, букв и символов подчеркивания, разделенных и предваряемых косой чертой, названной так из-за их сходства с путями файловой системы Unix . [5] [17] Путь к объекту выбирается запрашивающим процессом и должен быть уникальным в контексте данного шинного соединения. Пример допустимого пути к объекту: /org/kde/kspread/sheets/3/cells/4/5
. [17] Однако не обязательно (но и не рекомендуется) формировать иерархии внутри путей к объектам. [6] Конкретное соглашение об именах объектов службы полностью зависит от разработчиков такой службы, но многие разработчики предпочитают размещать их в пространстве имен , используя зарезервированное доменное имя проекта в качестве префикса (например, /org/kde ). [17]
Каждый объект неразрывно связан с конкретным шинным соединением, куда он был экспортирован, и, с точки зрения D-Bus, существует только в контексте такого соединения. Следовательно, чтобы иметь возможность использовать определенный сервис, клиент должен указать не только путь к объекту, предоставляющему желаемый сервис, но и имя шины, под которой к шине подключается процесс сервиса. [5] Это, в свою очередь, позволяет нескольким процессам, подключенным к шине, однозначно экспортировать разные объекты с одинаковыми путями к объектам.
Интерфейс определяет члены — методы и сигналы, — которые можно использовать с объектом. [17] Это набор объявлений методов (включая передаваемые и возвращаемые параметры) и сигналов (включая параметры), идентифицируемых именем, разделенным точкой, напоминающим нотацию интерфейсов языка Java . [17] [6] Пример допустимого имени интерфейса: org.freedesktop.Introspectable
. [6] Несмотря на схожесть, имена интерфейсов и шин не должны путаться. Объект D-Bus может реализовать несколько интерфейсов, но, по крайней мере, должен реализовать один, обеспечивая поддержку каждого метода и сигнала, определенных им. Комбинация всех интерфейсов, реализованных объектом, называется типом объекта . [5] [17]
При использовании объекта для клиентского процесса рекомендуется предоставлять имя интерфейса члена помимо имени члена, но это обязательно только в том случае, если существует двусмысленность, вызванная дублированием имен членов, доступных из разных интерфейсов, реализованных объектом [5] . [17] — в противном случае выбранный элемент не определен или ошибочен. С другой стороны, излучаемый сигнал всегда должен указывать, к какому интерфейсу он принадлежит.
Спецификация D-Bus также определяет несколько стандартных интерфейсов, которые объекты могут захотеть реализовать в дополнение к своим собственным интерфейсам. [16] Хотя это технически необязательно, большинство разработчиков сервисов D-Bus предпочитают поддерживать их в своих экспортируемых объектах, поскольку они предлагают клиентам D-Bus важные дополнительные функции, такие как самоанализ . [6] Эти стандартные интерфейсы: [16] [6]
Спецификация D-Bus определяет ряд административных операций шины (называемых «шинными службами»), которые должны выполняться с использованием объекта /org/freedesktop/DBus , который находится в имени шины org.freedesktop.DBus . [16] Каждая шина резервирует это специальное имя для себя и управляет любыми запросами, сделанными специально для этой комбинации имени шины и пути к объекту. Административные операции, предоставляемые шиной, определяются интерфейсом объекта org.freedesktop.DBus . Эти операции используются, например, для предоставления информации о состоянии шины [5] или для управления запросом и освобождением дополнительных известных имен шин. [16] [6]
D-Bus был задуман как универсальная система межпроцессного взаимодействия высокого уровня. Для достижения этих целей связь D-Bus основана на обмене сообщениями между процессами вместо «необработанных байтов». [5] [17] Сообщения D-Bus — это дискретные элементы высокого уровня, которые процесс может отправлять по шине другому подключенному процессу. Сообщения имеют четко определенную структуру (определены даже типы данных, переносимых в их полезной нагрузке), что позволяет шине проверять их и отклонять любое неправильно сформированное сообщение. В этом отношении D-Bus ближе к механизму RPC , чем к классическому механизму IPC, со своей собственной системой определения типов и собственной маршалингом . [5]
Шина поддерживает два режима обмена сообщениями между клиентом и сервисным процессом [5] :
Каждое сообщение D-Bus состоит из заголовка и тела. [17] Заголовок формируется несколькими полями, которые идентифицируют тип сообщения, отправителя, а также информацию, необходимую для доставки сообщения получателю (имя шины назначения, путь к объекту, имя метода или сигнала, имя интерфейса и т. д.). ). [17] [16] Тело содержит полезные данные, которые интерпретирует процесс-получатель — например, входные или выходные аргументы. Все данные кодируются в хорошо известном двоичном формате, называемом проводным форматом , который поддерживает сериализацию различных типов, таких как целые числа и числа с плавающей запятой, строки, составные типы и т. д. [16] , также называемый маршалингом .
Спецификация D-Bus определяет проводной протокол : как создавать сообщения D-Bus для обмена между процессами в рамках соединения D-Bus. Однако он не определяет базовый метод транспорта для доставки этих сообщений.
Большинство существующих реализаций D-Bus следуют архитектуре эталонной реализации. Эта архитектура состоит из двух основных компонентов: [5]
Библиотека libdbus (или ее эквивалент) внутри использует собственный механизм IPC нижнего уровня для транспортировки необходимых сообщений D-Bus между двумя процессами на обоих концах соединения D-Bus. Спецификация D-Bus не предписывает, какие именно транспортные механизмы IPC должны быть доступны для использования, поскольку именно коммуникационная библиотека решает, какие методы транспортировки она поддерживает. Например, в Unix-подобных операционных системах, таких как Linux, libdbus обычно использует сокеты домена Unix в качестве основного метода транспорта, но он также поддерживает сокеты TCP . [5] [17]
Коммуникационные библиотеки обоих процессов должны согласовать выбранный метод транспортировки, а также конкретный канал, используемый для их связи. Эта информация определяется тем, что D-Bus называет адресом . [6] [17] Сокеты домена Unix являются объектами файловой системы , и поэтому их можно идентифицировать по имени файла, поэтому действительным адресом будет unix:path=/tmp/.hiddensocket
. [5] [16] Оба процесса должны передать один и тот же адрес своим соответствующим коммуникационным библиотекам, чтобы установить соединение D-Bus между ними. Адрес также может предоставлять дополнительные данные в библиотеку связи в виде key=value
пар, разделенных запятыми. [6] [16] Таким образом, например, он может предоставлять информацию аутентификации определенному типу соединения, который его поддерживает.
Когда для реализации шины D-Bus используется демон шины сообщений, такой как dbus-daemon , все процессы, которые хотят подключиться к шине, должны знать адрес шины , адрес, по которому процесс может установить соединение D-Bus с центральным процессором. процесс шины сообщений. [5] [17] В этом сценарии демон шины сообщений выбирает адрес шины, а остальные процессы должны передать это значение в соответствующие библиотеки libdbus или эквивалентные. dbus-daemon определяет разные адреса шины для каждого экземпляра шины, который он предоставляет. Эти адреса определены в файлах конфигурации демона.
Два процесса могут использовать соединение D-Bus для обмена сообщениями непосредственно между ними, [21] но это не тот способ, которым обычно предполагается использовать D-Bus. Обычный способ — всегда использовать демон шины сообщений (т. е. dbus-daemon ) в качестве центральной точки связи, с которой каждый процесс должен установить двухточечное соединение D-Bus. Когда процесс — клиент или служба — отправляет сообщение D-Bus, процесс шины сообщений получает его в первую очередь и доставляет соответствующему получателю. Демон шины сообщений можно рассматривать как концентратор или маршрутизатор, отвечающий за доставку каждого сообщения к месту назначения путем его повторения через соединение D-Bus с процессом-получателем. [17] Процесс получателя определяется именем шины назначения в поле заголовка сообщения, [16] или информацией о подписке на сигналы, поддерживаемые демоном шины сообщений в случае сообщений о распространении сигнала. [6] Демон шины сообщений также может создавать свои собственные сообщения в ответ на определенные условия, например сообщение об ошибке процессу, который отправил сообщение на несуществующее имя шины. [17]
dbus-daemon расширяет набор функций, уже предоставляемый самим D-Bus, за счет дополнительных функций. Например, активация службы позволяет автоматически запускать службы при необходимости — когда первый запрос к любому имени шины такой службы поступает на демон шины сообщений. [5] Таким образом, служебные процессы не нужно запускать на этапе инициализации системы или пользователя, а также не требуют, чтобы они потребляли память или другие ресурсы, когда они не используются. Первоначально эта функция была реализована с использованием помощников setuid , [22] , но в настоящее время она также может быть предоставлена структурой активации службы systemd . [ нужна цитация ] Активация службы — это важная функция, которая облегчает управление жизненным циклом процесса служб (например, когда компонент рабочего стола должен запускаться или останавливаться). [17]
D-Bus был запущен в 2002 году Хэвоком Пеннингтоном, Алексом Ларссоном ( Red Hat ) и Андерсом Карлссоном. [8] Версия 1.0, считающаяся стабильной API , была выпущена в ноябре 2006 года. [23] [24]
Под сильным влиянием системы DCOP , используемой в версиях 2 и 3 KDE , D-Bus заменил DCOP в версии KDE 4 . [24] [25] Реализация D-Bus поддерживает большинство операционных систем POSIX , и существует порт для Windows . Он используется Qt 4 и более поздними версиями GNOME . В GNOME он постепенно заменил большую часть более раннего механизма Бонобо . Он также используется Xfce .
Одним из первых применений был (ныне устаревший) уровень аппаратной абстракции . HAL использовал D-Bus для экспорта информации об оборудовании, которое было добавлено или удалено с компьютера. [8]
Использование D-Bus постепенно выходит за пределы первоначального объема настольных сред и охватывает все большее количество системных сервисов. Например, сетевой демон NetworkManager , стек Bluetooth BlueZ и звуковой сервер PulseAudio используют D-Bus для предоставления части или всех своих услуг. systemd использует проводной протокол D-Bus для связи между systemctl и systemd, а также продвигает традиционные системные демоны в службы D-Bus, такие как logind . [26] Еще одним активным пользователем D-Bus является Polkit , чей демон полномочий политики реализован как сервис, подключенный к системной шине. [27]
Хотя существует несколько реализаций D-Bus, наиболее широко используемой является эталонная реализация libdbus , разработанная тем же проектом freedesktop.org, который разработал спецификацию. Однако libdbus — это низкоуровневая реализация, которая никогда не предназначалась для непосредственного использования разработчиками приложений, а служила справочным руководством для других реализаций D-Bus (например, включенных в стандартные библиотеки сред рабочего стола или в привязки языков программирования) . ). Сам проект freedesktop.org рекомендует авторам приложений вместо этого «использовать одну из привязок или реализаций более высокого уровня». [28] Преобладание libdbus как наиболее используемой реализации D-Bus привело к тому, что термины «D-Bus» и «libdbus» стали часто использоваться как синонимы, что приводило к путанице. [ нужна цитата ]
GDBus [9] — это реализация D-Bus на основе потоков GIO, включенных в GLib , предназначенная для использования GTK+ и GNOME . GDBus — это не оболочка libdbus, а полная и независимая реализация спецификации и протокола D-Bus. [29] MATE Desktop [30] и Xfce (версия 4.14), которые также основаны на GTK+ 3, также используют GDBus. [ нужна цитата ]
В 2013 году проект systemd переписал libdbus с целью упростить код [31] , но это также привело к значительному увеличению общей производительности D-Bus. В ходе предварительных тестов BMW обнаружила, что библиотека D-Bus systemd увеличила производительность на 360%. [32] В версии systemd 221 API sd-bus был объявлен стабильным. [33]
kdbus был проектом, целью которого было переопределить D-Bus как механизм однорангового межпроцессного взаимодействия, опосредованный ядром . Помимо повышения производительности, kdbus будет иметь преимущества, вытекающие из других функций ядра Linux , таких как пространства имен и аудит, [32] [36] безопасность за счет посредничества ядра, закрытия условий гонки и возможности использования D-Bus во время загрузки и завершения работы (как необходимо для systemd). [37] Включение kdbus в ядро Linux оказалось спорным, [38] и от него отказались в пользу BUS1, как более общего средства межпроцессного взаимодействия . [39]
Было разработано несколько привязок языков программирования для D-Bus, [40] например, для Java , C# , Ruby , Rust и Perl . [ нужна цитата ]
Одной из наиболее важных разработок настольных систем Linux является Desktop Bus (D-Bus), система передачи сообщений. D-Bus важен, поскольку он служит механизмом межпроцессного взаимодействия, который позволяет настольным приложениям взаимодействовать друг с другом [...].
D-Bus [...] предназначен для использования в качестве унифицированного промежуточного уровня под основными бесплатными средами рабочего стола.
Что касается варианта использования внутри сеанса рабочего стола, рабочие столы GNOME и KDE имеют значительный предыдущий опыт работы с различными решениями IPC, такими как CORBA и DCOP.
D-Bus создан на основе этого опыта и тщательно адаптирован для удовлетворения потребностей, в частности, настольных проектов.
D-Bus был впервые создан для замены CORBA-подобной компонентной модели, лежащей в основе среды рабочего стола GNOME.
Подобно DCOP (который используется KDE), D-Bus станет стандартным компонентом основных бесплатных сред рабочего стола для GNU/Linux и других платформ.
мы работаем над переносом вещей на настоящую пользовательскую шину, которая есть только одна на каждого пользователя в системе, независимо от того, сколько раз этот пользователь входит в систему.
Существуют также некоторые реализации протокола D-Bus для таких языков, как C#, Java и Ruby.
Они не используют эталонную реализацию libdbus.
построен на основе общей структуры передачи сообщений «один к одному», которую могут использовать любые два приложения для прямого взаимодействия (без использования демона шины сообщений).
С момента создания systemd это была система IPC, в которой он предоставляет свои интерфейсы.
Низкоуровневая реализация в первую очередь не предназначена для использования авторами приложений.
Скорее, это основа для связывания авторов и ссылка для повторных реализаций.
Если вы можете это сделать, рекомендуется использовать одну из привязок или реализаций более высокого уровня.
dbus-glib использует эталонную реализацию libdbus, а GDBus — нет.
Вместо этого он использует потоки GIO в качестве транспортного уровня и имеет собственную реализацию для настройки и аутентификации соединения D-Bus.