Русский
Русский
English
Статистика
Реклама

D-bus

Перевод Перевод вводной статьи от разработчиков D-BUS

26.11.2020 08:23:40 | Автор: admin

Руководство по D-BUS

https://dbus.freedesktop.org/doc/dbus-tutorial.html

Red Hat, Inc

<hp@pobox.com>

Дэвид Уиллер

Джон Палмиери

Red Hat, Inc.

<johnp@redhat.com>

Колин Уолтерс

Red Hat, Inc.

<walters@redhat.com>

Версия 0.5.0

Перевод Пластов И.В.

plastov.igor@yandex.ru

Документ в процессе разработки

Это руководство не завершено. Оно, вероятно, содержит некоторую полезную информацию, но также имеет много пробелов. Прямо сейчас вам также необходимо обратиться к спецификации D-Bus, справочной документации Doxygen и посмотреть несколько примеров того, как другие приложения используют D-Bus.

Определенно, приветствуется улучшение руководства - отправляйте свои исправления или предложения в список рассылки. Если вы создаете привязку D-Bus, пожалуйста, добавьте раздел в учебник для вашей привязки, хотя бы небольшой раздел с парой примеров.

Что такое D-Bus?

D-Bus - это система межпроцессного взаимодействия (IPC). Архитектурно он имеет несколько слоев:

  • Библиотекаlibdbus, которая позволяет двум приложениям подключаться друг к другу и обмениваться сообщениями.

  • Исполняемый файл демона шины сообщений, построенный наlibdbus, к которому могут подключаться несколько приложений. Демон может направлять сообщения от одного приложения к нулю или нескольким другим приложениям.

  • Библиотеки враперов или привязок основанных на частичном применении конкретных фреймворков. Например,libdbus-glibиlibdbus-qt. Также существуют привязки к таким языкам, как Python. Эти библиотеки-враперы представляют собой API-интерфейс, который следует использовать большинству людей, поскольку это упрощают детали программирования D-Bus.libdbusпредназначена для низкоуровневого бэкенда в привязках более высокого уровня. Большая часть APIlibdbusполезна только для реализации привязок.

Библиотекаlibdbusподдерживает только соединения точка-точка, подобноraw-сокету. Однако, вместо отправки по соединению потока байтов, вы отправляете сообщения. Сообщения имеют заголовок, определяющий его тип и тело, содержащее полезные данные.libdbusтакже абстрагирует конкретно используемый транспорт (сокеты или что-то еще) и обрабатывает такие детали, как аутентификация.

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

На обычном компьютере имеется несколько экземпляров демона шины. Первый экземпляр - это глобальный синглтон машины, то есть системный демон, похожий на sendmail или Apache. Этот экземпляр имеет строгие ограничения безопасности на то, какие сообщения он будет принимать, и используется для общесистемной связи. Остальные экземпляры создаются по одному для каждого сеанса входа пользователя. Эти экземпляры позволяют приложениям в сеансе пользователя взаимодействовать друг с другом.

Общесистемный и индивидуальные демоны разделены. Обычный внутрисессионный IPC не использует шину сообщений общесистемного процесса, и наоборот.

Применения D-Bus

В мире существует очень много технологий, заявленная цель которых - межпроцессное взаимодействие или сеть: CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE) и наверное еще сотни. Каждый из них предназначен для определенных типов использования. D-Bus разработан для двух конкретных случаев:

  • Связь между настольными приложениями в одном рабочем столе; для обеспечения интеграции сеанса рабочего стола в целом и решения проблем жизненного цикла процесса (когда компоненты рабочего стола запускаются и останавливаются).

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

Для случая использования в рамках сеанса рабочего стола рабочие столы GNOME и KDE имеют значительный предыдущий опыт работы с различными решениями IPC, такими как CORBA и DCOP. D-Bus основан на этом опыте и тщательно адаптирован для удовлетворения потребностей, в частности, таких настольных проектов. D-Bus может подходить или не подходить для других приложений; в FAQ есть некоторые сравнения с другими системами IPC.

Проблема, решаемая общесистемным случаем или случаем связи с ОС, хорошо объясняется следующим текстом из проекта Linux Hotplug:

Пробел в текущей поддержке Linux заключается в том, что в настоящее время не поддерживаются политики с каким-либо динамическим компонентом взаимодействия с пользователем. Например, это часто требуется при первом подключении сетевого адаптера или принтера, а также для определения подходящих мест для монтирования дисков. Казалось бы, такие действия могут поддерживаться в любом случае, когда можно идентифицировать ответственного человека: однопользовательские рабочие станции или любая система, которая администрируется удаленно.

Это классическая проблема удаленного системного администратора, когда в случае горячего подключения должно доставляться событие из его домена безопасности (в данном случае ядра операционной системы) в другой (рабочий стол для вошедшего в систему пользователя или удаленного системного администратора). Любой эффективный ответ должен идти другим путем: удаленный домен предпринимает действия, позволяющие ядру выяснить возможности устройства. (Действие часто может быть выполнено асинхронно, например, позволяя новому оборудованию бездействовать до завершения переговоров.) На момент написания этой статьи в Linux не было широко распространенных решений таких проблем. Однако новые разработки D-Bus могут начать решать эту проблему.

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

  • Двоичный протокол, предназначенный для асинхронного использования (в духе протокола X Window System);

  • Постоянные и надежные соединения остаются открытыми все время;

  • Шина сообщений - это демон, а не рой или распределенная архитектура;

  • Многие вопросы реализации и деплоя описаны, а не остаются неоднозначными / настраиваемыми / подключаемыми.

  • Семантика подобна существующей системе DCOP, что позволяет KDE легко ее адаптировать.

Функции безопасности для поддержки режима общесистемной шины сообщений.

Концепции

Некоторые базовые концепции применимы независимо от того, какую платформу приложения вы используете для написания приложения D-Bus. Однако конкретный код, который вы напишете, будет отличаться для приложений GLib, Qt и Python.

Вот диаграмма, которая может помочь вам наглядно представить следующие концепции.

Нативные объекты /и пути к объектам

Вероятно, в вашем фреймворке, определено, что такое объект; обычно это базовый класс. Например:java.lang.Object, GObject, QObject,базовый объект Python или что-то еще. Назовем их нативным объектом.

Протокол D-Bus низкого уровня и соответствующий APIlibdbusне оперирует нативными объектами. Однако он предоставляет концепцию, называемую путем к объекту. Идея пути к объекту заключается в том, что привязки более высокого уровня могут давать имена экземплярам собственных объектов и позволяет удаленным приложениям обращаться к ним.

Путь к объекту выглядит как путь в файловой системе, например, объект может называться

/org/kde/kspread/sheet/3/cells/4/5

. Удобочитаемые пути - это хороший тон, но вы можете создать объект с именем

/com/mycompany/c5yo817y0c1y1c5b

, если это имеет смысл для вашего приложения.

Разумно начинать пути к объектам с их пространств имен - с компонентов вашего доменного имени (например,

/org/kde

). Благодаря этому разные модули кода в одном процессе не будут мешать друг другу.

Методы и сигналы

У каждого объекта есть члены. Два вида членов - это методы и сигналы. Методы - это операции, которые могут быть вызваны у объекта, с необязательным вводом (они же аргументы или входные параметры) и выводом (они же возвращаемые значения или исходящие параметры).Сигналы - это широковещательные передачи от объекта всем заинтересованным наблюдателям объекта; сигналы могут содержать полезную нагрузку.

На методы, и сигналы ссылаются по их имени, например Frobate или OnClicked.

Интерфейсы

Каждый объект поддерживает один или несколько интерфейсов. Понимайте интерфейс как именованную группу методов и сигналов, как в GLib, Qt или Java. Интерфейсы определяют тип экземпляра объекта.

DBus идентифицирует интерфейсы с помощью простой строки с именами, например

org.freedesktop.Introspectable

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

Прокси

Прокси-объект - это удобный нативный объект, созданный для представления удаленного объекта в другом процессе. Низкоуровневый DBus API предполагает создание вручную сообщения о вызове метода, его отправку, а затем получение и ручную обработку сообщения с ответом метода. Привязки более высокого уровня предоставляют прокси в качестве альтернативы.Прокси выглядят как обычный нативный объект, но когда вы вызываете метод прокси-объекта, привязка преобразует его в сообщение вызова метода DBus, ожидает ответного сообщения, распаковывает возвращаемое значение и возвращает его из нативного метода.

В псевдокоде программирование без прокси может выглядеть так:

Message message = new Message("/remote/object/path", "MethodName", arg1, arg2);          Connection connection = getBusConnection();          connection.send(message);          Message reply = connection.waitForReply(message);          if (reply.isError()) {      } else {        Object returnValue = reply.getReturnValue();      }</pre></div><div class="standard" id="magicparlabel-247" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Программирование с использованием прокси может выглядеть так:</div><div class="float-listings" style="border: 2px solid black; padding: 1ex; margin: 1ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><pre class="listings">Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path");      Object returnValue = proxy.MethodName(arg1, arg2);</pre></div><h2 class="section_" id="magicparlabel-254" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Шинные имена</h2><div class="standard" id="magicparlabel-260" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Когда приложение подключается к демону шины, демон немедленно присваивает ему имя, называемое уникальным именем подключения.<span>&nbsp;</span><a id="magicparlabel-264"></a>Уникальное имя начинается с символа ':' (двоеточия). Эти имена, во время существования шинного демона никогда не используются повторно - то есть вы знаете, что данное имя всегда будет относиться к одному и тому же приложению. Примером уникального имени может быть<pre class="listings">:34-907</pre>. Цифры после двоеточия не имеют иного смысла, кроме их уникальности.</div><div class="standard" id="magicparlabel-269" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Когда имя сопоставляется с подключением определенного приложения, считается, что это приложение<span>&nbsp;</span><span style="font-style: oblique;">владеет</span><span>&nbsp;</span>этим именем.</div><div class="standard" id="magicparlabel-270" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Приложения могут запрашивать дополнительные общеизвестные (<span style="font-style: oblique;">well-known</span>) имена. Например, вы можете написать спецификацию для определения имени<pre class="listings">com.mycompany.TextEditor</pre>. В вашем определении можно указать, что для владения этим именем приложение должно иметь объект с путём<pre class="listings">/com/mycompany/TextFileManager</pre>,</div><div class="standard" id="magicparlabel-279" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">поддерживающий интерфейс<pre class="listings">org.freedesktop.FileHandler</pre>.</div><div class="standard" id="magicparlabel-284" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Затем приложения, для вызова методов, могут отправлять сообщения на это шинное имя, объект и интерфейс.</div><div class="standard" id="magicparlabel-285" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Вы можете думать об уникальных именах как об IP-адресах, а об общеизвестных именах как о доменных именах. Таким образом,<pre class="listings">com.mycompany.TextEditor</pre>может отображаться например как<pre class="listings">:34-907</pre>так же, как<pre class="listings">mycompany.com</pre>соответствовать чему-то вроде<pre class="listings">192.168.0.5</pre>.</div><div class="standard" id="magicparlabel-302" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Имена, помимо маршрутизации сообщений, имеют второе важное применение. Они используются для отслеживания жизненного цикла. Когда приложение завершает работу (или аварийно закрывается), ядро операционной системы закрывается его соединение с шиной сообщений. Затем шина сообщений отправляет сообщения уведомления, информирующие остальные приложения о том, что имена приложения потеряли своего владельца. Отслеживая эти уведомления, ваше приложение может надежно отслеживать время жизни других приложений.</div><div class="standard" id="magicparlabel-303" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Шинные имена также могут использоваться для координации одноэкземплярных приложений. Если, например, вы хотите быть уверенным, что работает только одно приложение<pre class="listings">com.mycompany.TextEditor</pre>, закрывайте приложение текстового редактора, если такое шинное имя уже имеет владельца.</div><h2 class="section_" id="magicparlabel-308" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Адреса</h2><div class="standard" id="magicparlabel-314" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Приложения, использующие D-Bus, являются либо серверами, либо клиентами. Сервер прослушивает входящие соединения; клиент подключается к серверу. Как только соединение установлено, образуется симметричный поток сообщений. Различие клиент-сервер имеет значение только при настройке соединения.</div><div class="standard" id="magicparlabel-315" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Если вы, используете демон шины, ваше приложение будет клиентом демона шины. То есть демон шины прослушивает соединения, а ваше приложение инициирует соединение с демоном шины.</div><div class="standard" id="magicparlabel-316" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">D-Bus адрес указывает, где сервер будет слушать, и куда будет подключаться клиент. Например, адрес<pre class="listings">unix:path=/tmp/abcdef</pre>указывает, что сервер будет прослушивать сокет домена UNIX с путём<pre class="listings">/tmp/abcdef</pre>, и клиент будет подключаться к этому сокету. Адрес может также определять TCP/IP сокеты или любой другой транспорт, который будет определен в будущих итерациях спецификации D-Bus.</div><div class="standard" id="magicparlabel-325" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">При использовании D-Bus с демоном шины сообщений,<span>&nbsp;</span><span style="font-style: oblique;">libdbus</span><span>&nbsp;</span>автоматически обнаруживает адрес сеансового демона шины, считывая переменную среды. Он обнаруживает демон общесистемной шины, проверяя известный путь сокета домена UNIX (хотя вы можете переопределить этот адрес с помощью переменной среды).</div><div class="standard" id="magicparlabel-326" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Если вы используете D-Bus без демона шины, то вам решать, какое приложение будет сервером, а какое - клиентом, а также указать механизм для согласования адреса сервера. Это нетипичный случай.</div><h2 class="section_" id="magicparlabel-327" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Большаяконцептуальная картина</h2><div class="standard" id="magicparlabel-333" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Собирая все эти концепции воедино, для вызова конкретного метода для конкретного экземпляра объекта, необходимо указать несколько вложенных компонентов:</div><div class="standard" id="magicparlabel-334" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Шинное имя указано в квадратных скобках, чтобы указать, что оно необязательно - вы указываете имя только для маршрутизации вызова метода в нужном приложение при использовании демона шины. Если у вас есть прямое соединение с другим приложением, то демон шины отсутствует и шинные имена не используются.</div><div class="float-listings" style="border: 2px solid black; padding: 1ex; margin: 1ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><pre class="listings">Адрес -> [Шинное имя] -> Путь -> Интерфейс -> Метод</pre></div><div class="standard" id="magicparlabel-339" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Интерфейс также не является обязательным, в первую очередь по историческим причинам; DCOP не требует указания интерфейса, вместо этого просто запрещает дублирование имен методов в одном экземпляре объекта. Таким образом, D-Bus позволит вам не указывать интерфейс, но если имя вашего метода неоднозначно, то не определено, какой метод будет вызван.</div><h2 class="section_" id="magicparlabel-340" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><a id="sec______________________"></a>За кулисамисообщения</h2><div class="standard" id="magicparlabel-346" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">D-Bus работает, отправляя сообщения между процессами. Если вы используете привязку достаточно высокого уровня, возможно вам не понадобится работать с сообщениями напрямую.</div><div class="standard" id="magicparlabel-347" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Есть 4 типа сообщений:</div><ul class="itemize" id="magicparlabel-348" style="margin-top: 0.7ex; margin-bottom: 0.7ex; margin-left: 3ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><li class="itemize_item">Сообщения о вызове метода запрашивают вызов метода для объекта;</li><li class="itemize_item">Сообщения о завершении метода возвращают результаты вызова метода;</li><li class="itemize_item">Сообщения об ошибках возвращают исключение, возникшее при вызове метода;</li><li class="itemize_item">Сигнальные сообщения - это уведомления о том, что данный сигнал был послан (что произошло событие). Вы также можете понимать это как сообщения о событиях.</li></ul><div class="standard" id="magicparlabel-352" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Вызов метода очень просто сопоставляется с сообщениями: вы отправляете сообщение о вызове метода и получаете в ответ либо сообщение о завершении метода, либо сообщение об ошибке.</div><div class="standard" id="magicparlabel-353" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">У каждого сообщения есть заголовок, содержащий поля, и тело, включающее аргументы. Вы можете думать о заголовке как о маршрутной информации для сообщения, а о теле - как о полезной нагрузке. Поля заголовка могут включать шинное имя отправителя, шинное имя назначения, имя метода или сигнала и так далее. Одно из полей заголовка - это сигнатура типа, описывающая значения, находящиеся в теле. Например, буква i означает 32-битное целое число, поэтому сигнатура ii означает, что полезная нагрузка содержит два 32-битных целых числа.</div><h2 class="section_" id="magicparlabel-354" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><a id="chap_______________"></a>За кулисамивызова метода</h2><div class="standard" id="magicparlabel-360" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Вызов метода в DBus состоит из двух сообщений; сообщение о вызове метода, отправленное из процесса A в процесс B, и ответное сообщение соответствующего метода, отправленное из процесса B в процесс A. И вызов, и ответное сообщение маршрутизируются через демон шины. Вызывающий включает в каждое сообщение о вызове отличающийся серийный номер, ответное сообщение содержит этот же номер, чтобы вызывающий процесс мог сопоставить ответы с вызовами.</div><div class="standard" id="magicparlabel-361" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Сообщение о вызове метода будет содержать любые аргументы метода. Ответное сообщение может указывать на ошибку или содержать данные, возвращаемые методом.</div><div class="standard" id="magicparlabel-362" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Вызов метода в DBus происходит следующим образом:</div><ul class="itemize" id="magicparlabel-363" style="margin-top: 0.7ex; margin-bottom: 0.7ex; margin-left: 3ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><li class="itemize_item">Привязка языка может предоставлять прокси, так что вызов метода внутрипроцессного объекта вызывает метод удаленного объекта в другом процессе. Если это так, приложение вызывает метод на прокси-сервере, и прокси создает сообщение о вызове метода для отправки удаленному процессу.</li><li class="itemize_item">Для более низкоуровневых API приложение может создать сообщение о вызове метода само, без использования прокси.</li><li class="itemize_item">В любом случае сообщение о вызове метода содержит: шинное имя, принадлежащее удаленному процессу, название метода, аргументы метода, путь к объекту внутри удаленного процесса и, опционально, имя интерфейса, определяющего метод.</li><li class="itemize_item">Сообщение о вызове метода отправляется демону шины.</li><li class="itemize_item">Демон шины просматривает шинное имя назначения. Если это имя принадлежит процессу, демон шины перенаправляет вызов метода этому процессу. В противном случае демон шины создает сообщение об ошибке и отправляет его обратно в качестве ответа на сообщение о вызове метода.</li><li class="itemize_item">Принимающий процесс распаковывает сообщение о вызове метода. В простой ситуации низкоуровневого API он может немедленно запустить метод и отправить ответное сообщение метода демону шины. При использовании API привязки высокого уровня, привязка может проверять путь к объекту, интерфейс и имя метода и преобразовывать сообщение вызова метода в вызов метода для нативного объекта (GObject, java.lang.Object, QObject, и т.д.), а затем преобразовать возвращаемое значение из нативного метода в ответное сообщение метода.</li><li class="itemize_item">Демон шины получает ответное сообщение метода и отправляет его процессу, который вызывал метод.</li><li class="itemize_item">Процесс, вызывавший метод, просматривает ответ метода и использует любые возвращаемые значения, находящиеся в ответе. Ответ также может указывать на то, что произошла ошибка. При использовании привязки ответное сообщение метода может быть преобразовано в возвращаемое значение прокси-метода или в исключение.</li></ul><div class="standard" id="magicparlabel-371" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Демон шины никогда не меняет порядок сообщений. То есть, если вы отправите два сообщения о вызове метода одному и тому же получателю, они будут получены в том порядке, в котором они были отправлены. Однако получатель не обязан отвечать на вызовы по порядку; например, он может обрабатывать каждый вызов метода в отдельном потоке и возвращать ответные сообщения в неопределенном порядке в зависимости от того, в каком порядке завершаются потоки. Вызовы методов имеют уникальный серийный номер, используемый вызывающим методом для сопоставления ответных сообщений с сообщениями вызова.</div><h2 class="section_" id="magicparlabel-372" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">За кулисамиизлучения сигнала</h2><div class="standard" id="magicparlabel-378" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Сигнал в DBus состоит из одного сообщения, отправляемого одним процессом любому количеству других процессов. То есть<span>&nbsp;</span><a id="magicparlabel-382"></a>сигнал - это однонаправленная трансляция. Сигнал может содержать аргументы (полезные данные), но поскольку он является широковещательным, он никогда не имеет возвращаемого значения. Сравните это с вызовом метода (см.<span>&nbsp;</span><a href="#chap_______________">#</a>), где сообщение о вызове метода имеет соответствующее ответное сообщение метода.</div><div class="standard" id="magicparlabel-383" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Эмитент (он же отправитель) сигнала не знает получателей сигнала. Получатели регистрируются с помощью демона шины для получения сигналов на основе правил соответствия - эти правила обычно включают отправителя и имя сигнала. Демон шины отправляет каждый сигнал только тем получателям, которые проявили интерес к этому сигналу.</div><div class="standard" id="magicparlabel-384" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Сигнал в DBus передается следующим образом:</div><ul class="itemize" id="magicparlabel-385" style="margin-top: 0.7ex; margin-bottom: 0.7ex; margin-left: 3ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><li class="itemize_item">Создается сигнальное сообщение и отправляется демону шины. При использовании низкоуровневого API это можно сделать вручную, с некоторыми привязками это может быть сделано за вас с помощью привязки, когда нативный объект испускает нативный сигнал или событие.</li><li class="itemize_item">Сигнальное сообщение содержит имя интерфейса, определяющего сигнал, название сигнала, шинное имя процесса, отправляющего сигнал и любые аргументы.</li><li class="itemize_item">Любой процесс на шине сообщений может зарегистрировать правила сопоставления, указывающие, какие сигналы ему интересны. У шины есть список зарегистрированных правил сопоставления.</li><li class="itemize_item">Демон шины исследует сигнал и определяет, какие процессы в нем заинтересованы. Он отправляет этим процессам сигнальное сообщение.</li><li class="itemize_item">Каждый процесс, получивший сигнал, решает, что с ним делать; при использовании привязки, привязка может излучать нативный сигнал для прокси-объекта. При использовании низкоуровневого API процесс может просто взглянуть на отправителя сигнала и имя и решить, что на основании этого сделать.</li></ul><h2 class="section_" id="magicparlabel-390" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Интроспекция</h2><div class="standard" id="magicparlabel-396" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Объекты D-Bus могут поддерживать интерфейс<pre class="listings">org.freedesktop.DBus.Introspectable</pre>. У этого интерфейса есть один метод<span>&nbsp;</span><span style="font-style: oblique;">Introspect</span>, который не принимает аргументов и возвращает строку XML. Строка XML описывает интерфейсы, методы и сигналы объекта. См. Спецификацию D-Bus для получения более подробной информации об этом формате интроспекции.</div><h2 class="section_" id="magicparlabel-406" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">GLib API</h2><div class="standard" id="magicparlabel-407" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Рекомендуемый GLib API для D-Bus - GDBus, который распространяется с GLib начиная с версии 2.26. Здесь он не описана, для получения подробной информации об использовании GDBus см. Документацию GLib по ссылке:</div><div class="standard" id="magicparlabel-408" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">https:<a href="http://personeltest.ru/aways/developer.gnome.org/gio/stable/gdbus-convenience.html">//developer.gnome.org/gio/stable/gdbus-convenience.html</a></div><div class="standard" id="magicparlabel-409" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Также существует более старый API,<span>&nbsp;</span><span style="font-style: oblique;">dbus-glib</span>. Он устарел и не должен использоваться в новом коде. По возможности также рекомендуется переносить существующий код из<span>&nbsp;</span><span style="font-style: oblique;">dbus-glib</span><span>&nbsp;</span>в GDBus.</div><h2 class="section_" id="magicparlabel-410" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Python API</h2><div class="standard" id="magicparlabel-416" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Python API,<span>&nbsp;</span><span style="font-style: oblique;">dbus-python</span>, теперь документирован отдельно в руководстве<span>&nbsp;</span><span style="font-style: oblique;">dbus-python</span></div><div class="standard" id="magicparlabel-417" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><a href="http://personeltest.ru/away/dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html">http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html</a></div><div class="standard" id="magicparlabel-418" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">(также доступен в<span>&nbsp;</span><span style="font-style: oblique;">doc/tutorial.txt</span><span>&nbsp;</span>и<span>&nbsp;</span><span style="font-style: oblique;">doc/tutorial.html</span>, если он собран с помощью<span>&nbsp;</span><span style="font-style: oblique;">python-documenttils</span>, в исходном дистрибутиве<span>&nbsp;</span><span style="font-style: oblique;">dbus-python</span>).</div><h2 class="section_" id="magicparlabel-419" style="font-weight: bold; font-size: x-large; margin-top: 1.3ex; margin-bottom: 0.7ex; text-align: left; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Qt API</h2><div class="standard" id="magicparlabel-425" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Привязка Qt для<span>&nbsp;</span><span style="font-style: oblique;">libdbus</span>, QtDBus, распространяется с Qt начиная с версии 4.2. Здесь она не описана. Для получения подробной информации о том, как использовать QtDBus см. документацию Qt:</div><div class="standard" id="magicparlabel-426" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><a href="http://personeltest.ru/away/qt-project.org/doc/qt-5/qtdbus-index.html">http://qt-project.org/doc/qt-5/qtdbus-index.html</a>.</div><div class="standard" id="magicparlabel-427" style="margin-bottom: 2ex; color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"></div><div class="index chapter" style="color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><h1 class="chapter">I</h1></div><!--EndFragment-->
Подробнее..

Новый sd-bus API от systemd

09.04.2021 00:16:01 | Автор: admin

В новом выпуске systemd v221 мы представляем API sd-bus, поставляемый со стабильной версией systemd. sd-bus - это наша минимальная библиотека D-Bus IPC на языке программирования Си, поддерживающая в качестве бэкэндов как классическую D-Bus на основе сокетов, так и kdbus. Библиотека была частью systemd в течение некоторого времени, но использовалась только внутри проекта, поскольку мы хотели свободно вносить изменения в API, не затрагивая внешних пользователей. Однако теперь, начиная с v221, мы уверены, что сделали стабильный API.

В этом посте я предоставляю обзор библиотеки sd-bus, краткое повторение основ D-Bus и его концепций, а также несколько простых примеров того, как писать клиенты и сервисы D-Bus с её помощью.

Что такое D-Bus?

Давайте начнем с быстрого напоминания, что на самом деле представляет собой D-Bus. Это мощная универсальная система IPC для Linux и других операционных систем. Он определяет такие понятия, как шины, объекты, интерфейсы, методы, сигналы, свойства. Она предоставляет вам детальный контроль доступа, богатую систему типов, лёгкое обнаружение, самодиагностику, мониторинг, надежную многоадресную рассылку, запуск служб, передачу файловых дескрипторов и многое другое. Есть привязки для многих языков программирования, которые используются в Linux.

D-Bus является основным компонентом систем Linux более 10 лет. Это, безусловно, наиболее широко распространенная локальная система IPC высокого уровня в Linux. С момента создания systemd - это была система IPC, в которой она предоставляла свои интерфейсы. И даже до systemd это была система IPC, которую Upstart использовал для своих интерфейсов. Она используется GNOME, KDE и множеством системных компонентов.

К D-Bus относится как спецификация, так и эталонной реализация. Эталонная реализация предоставляет как компонент сервера шины, так и клиентскую библиотеку. Хотя существует множество других популярных последующих реализаций клиентской библиотеки, как для Си, так и для других языков программирования, единственная широко используемая серверная сторона - это та, которая указана в эталонной реализации. (Однако проект kdbus работает над предоставлением альтернативы этой реализации сервера в качестве компонента ядра.)

D-Bus в основном используется как локальный IPC поверх сокетов AF_UNIX. Однако протокол также можно использовать поверх TCP/IP. Он изначально не поддерживает шифрование, поэтому использование D-Bus напрямую через TCP обычно не является хорошей идеей. Можно объединить D-Bus с транспортом, таким как ssh, чтобы защитить его. systemd использует это, чтобы сделать многие из своих API доступными удаленно.

Часто задаваемый вопрос о D-Bus: почему он вообще существует, учитывая, что сокеты AF_UNIX и FIFO уже есть в UNIX и долгое время успешно используются. Чтобы ответить на этот вопрос, давайте сравним D-Bus с популярными сегодня веб-технологиями: AF_UNIX/FIFO для D-Bus тоже самое, что TCP для HTTP/REST. В то время, как сокеты AF_UNIX/FIFO только перекладывают необработанные байты между процессами, D-Bus определяет фактическую кодировку сообщений и добавляет такие концепции, как транзакция вызова методов, система объектов, механизмы безопасности, многоадресная передача сообщений и многое другое.

Из нашего более чем 10-летнего опыта работы с D-Bus сегодня мы знаем, что, хотя есть некоторые области, в которых мы можем что-то улучшить (и мы работаем над этим, как с kdbus, так и с sd-bus), в целом это очень хорошо спроектированная система, которая выдержала испытание временем, выдержала хорошо и получила широкое признание. Если бы сегодня мы сели и разработали совершенно новую систему IPC, включающую весь опыт и знания, полученные с помощью D-Bus, я уверен, что результат был бы очень близок к тому, что уже есть в D-Bus.

Короче говоря: D-Bus великолепен. Если вы разрабатываете проект для Linux и вам нужен локальный IPC, то он должен быть вашим первым выбором. Не только потому, что D-Bus хорошо спроектирован, но и потому, что есть не так много альтернатив, которые могли бы покрыть аналогичную функциональность.

Для чего подходит sd-bus?

Давайте обсудим, для чего написана библиотека sd-bus, как она соотносится с другими библиотеками D-Bus и почему она может стать библиотекой для вашего проекта.

Для языка программирования Си существуют две популярные библиотеки D-Bus: libdbus, поставляемая в эталонной реализации D-Bus, а также GDBus, компонент GLib, низкоуровневой инструментальной библиотеки GNOME.

Из этих двух библиотек libdbus намного старше, так как она была написана во время составления спецификации. Она была написана с упором на то, чтобы быть переносимой и полезной в качестве серверной части для привязок языков более высокого уровня. Обе эти цели требовали, чтобы API был очень универсальным, в результате чего получился относительно сложный в использовании API в котором отсутствуют элементы, которые делают его легким и интересным для использования из Си. Он предоставляет строительные блоки, но в нём мало инструментов, чтобы упростить строительство дома из них. С другой стороны, библиотека подходит для большинства случаев использования (например, она OOM безопасна, что делает ее подходящей для написания системного программного обеспечения самого низкого уровня) и переносима в операционные системы, такие как Windows или более экзотические UNIX.

GDBus - это гораздо более новая реализация. Она была написана после значительного опыта использования оболочки GLib/GObject вокруг libdbus. GDBus реализована с нуля, не имеет общего кода с libdbus. Её дизайн существенно отличается от libdbus, он содержит генераторы кода, чтобы упростить размещение объектов GObject на шине или взаимодействие с объектами D-Bus как с объектами GObject. Она переводит типы данных D-Bus в GVariant, который является мощным форматом сериализации данных GLib. Если вы привыкли к программированию в стиле GLib, тогда вы почувствуете себя как дома, использовать сервисы и клиенты D-Bus с её помощью намного проще, чем с libdbus.

С sd-bus мы теперь предоставляем третью реализацию, не разделяющую кода ни с libdbus, ни с GDBus. Для нас основное внимание было уделено обеспечению своего рода промежуточного звена между libdbus и GDBus: низкоуровневой библиотекой Си, с которой действительно интересно работать, которая имеет достаточно синтаксического сахара, чтобы упростить создание клиентов и сервисов, но, с другой стороны, более низкоуровневой, чем GDBus/GLib/GObject/GVariant. Чтобы использовать её в различных компонентах системного уровня systemd, она должен быть компактной и безопасной для OOM. Еще одним важным моментом, на котором мы хотели сосредоточиться, была поддержка бэкэнда kdbus с самого начала в дополнение к транспорту сокетов исходной спецификации D-Bus (dbus1). Фактически, мы хотели спроектировать библиотеку ближе к семантике kdbus, чем к dbus1, где-то были бы отличия, но при этом чтобы хорошо охватывались оба транспорта. В отличие от libdbus или GDBus, переносимость не является приоритетом для sd-bus, вместо этого мы стараемся максимально использовать платформу Linux и раскрывать конкретные концепции Linux везде, где это выгодно. Наконец, производительность также была проблемой (хотя и второстепенной): ни libdbus, ни GDBus не побьют рекорды скорости. Мы хотели улучшить производительность (пропускную способность и задержку), но для нас важнее простота и правильность. Мы считаем, что результат нашей работы вполне соответствует нашим целям: библиотеку приятно использовать, она поддерживает kdbus и сокеты в качестве серверной части, относительно минимальна, а производительность существенно выше, чем у libdbus и GDBus.

Вот краткие рекомендации, чтобы решить, какой из трех API использовать для вашего проекта на Си:

  • Если вы разрабатываете проект GLib/GObject, GDBus определенно будет вашим лучшим выбором.

  • Если для вас важна переносимость на ядра, отличные от Linux, включая Windows, Mac OS и другие UNIX, используйте либо GDBus (что более или менее означает использование GLib/GObject), либо libdbus (что требует большого количества ручной работы).

  • В противном случае я бы рекомендовал использовать sd-bus.

(Я не рассматриваю здесь C++, речь идет только о простом Си. Но обратите внимание: если вы используете Qt, то QtDBus является предпочтительным API D-Bus, являясь оболочкой для libdbus.)

Введение в концепции D-Bus

Непосвященному D-Bus обычно кажется относительно непрозрачной технологией. В нем используется множество концепций, которые на первый взгляд кажутся излишне сложными и избыточными. Но на самом деле они имеют большой смысл. Давайте посмотрим:

  • Шина - это то место, где вы ищете услуги IPC. Обычно существует два типа шин: системная шина, одна на систему, на которой располагаются системные службы; и пользовательская шина, одна на каждого пользователя, на которой располагаются пользовательские службы, такие как адресная книга или почтовый клиент. (Первоначально пользовательская шина была на самом деле сеансовой это значит, что вы получаете несколько шин, если входите в систему много раз как один и тот же пользователь, и в большинстве настроек так и остается, но мы работаем над истинной пользовательской шиной, которая существует в единственном экземпляре для каждого пользователя в системе, независимо от того, сколько раз этот пользователь входит в систему.)

  • Сервис - это программа, которая предлагает некоторый IPC API на шине. Служба идентифицируется именем в обратной нотации доменного имени. Таким образом, служба org.freedesktop.NetworkManager на системной шине - это то место, где доступны API-интерфейсы NetworkManager, а org.freedesktop.login1 на системной шине - это место, где доступны API-интерфейсы systemd-logind.

  • Клиент - это программа, которая использует некоторый IPC API на шине. Он общается с сервисом, контролирует его и, как правило, не предоставляет никаких услуг самостоятельно. При этом границы размыты, и многие службы также являются клиентами других служб. Часто термин узел используется как обобщение для обозначения сервиса или клиента.

  • Путь к объекту - это идентификатор объекта в определенной службе. В некотором смысле это сравнимо с указателем Си, поскольку именно так вы обычно ссылаетесь на объект Си, если пишите объектно-ориентированные программы на Си. Однако указатели Си - это просто адреса памяти, и передача адресов памяти другим процессам не имеет смысла, поскольку они относятся к адресному пространству сервиса и клиент не может получить достап к ним. Таким образом, разработчики D-Bus придумали концепцию пути к объекту, который представляет собой просто строку, которая выглядит как путь в файловой системе. Пример: /org/freedesktop/login1 - это путь к объекту менеджер сервиса org.freedesktop.login1 (который, как мы помним из вышеизложенного, является сервисом systemd-logind). Поскольку пути к объектам структурированы как пути файловой системы, их можно аккуратно упорядочить в виде дерева и получить полное дерево объектов. Например, вы найдете все пользовательские сеансы, которыми управляет systemd-logind в ветке /org/freedesktop/login1/session, к примеру: /org/freedesktop/login1/session/_7, /org/freedesktop/login1/session./_55 и так далее. Как сервисы именуют свои объекты и размещают их в дереве, полностью зависит от их разработчиков.

  • Каждый объект, который определяется путем, имеет один или несколько интерфейсов. Интерфейс - это набор сигналов, методов и свойств (вместе называемых членами), которые связаны друг с другом. Концепция интерфейсов D-Bus на самом деле в значительной степени идентична тому, что вы знаете из языков программирования, таких как Java, которые её поддерживают. Какие интерфейсы реализует объект, определяют разработчики сервиса. Имена интерфейсов имеют обратную нотацию доменных имен, как и имена сервисов. (Да, это, по общему признанию, сбивает с толку, поскольку для простых сервисов довольно часто встречается использование строки имени сервиса также в качестве имени интерфейса.) Тем не менее, несколько интерфейсов стандартизированы, и вы найдете их доступными для многих объектов, реализуемых различными сервисами. В частности, это org.freedesktop.DBus.Introspectable, org.freedesktop.DBus.Peer и org.freedesktop.DBus.Properties.

  • Интерфейс может содержать методы. Слово метод более или менее просто причудливое определение для функции, и этот термин используется почти так же в объектно-ориентированных языках, таких как Java. Наиболее распространенное взаимодействие между узлами D-Bus заключается в том, что один узел вызывает метод на другом узле и получает ответ. Метод D-Bus принимает и возвращает несколько параметров. Параметры передаются безопасным для типов способом, а информация о типе включается в данные интроспекции, которые вы можете запросить у каждого объекта. Обычно имена методов (и других типов членов) следуют синтаксису CamelCase. Например, systemd-logind предоставляет метод ActivateSession в интерфейсе org.freedesktop.login1.Manager, который доступен в объекте /org/freedesktop/login1 сервиса org.freedesktop.login1.

  • Сигнатура описывает набор параметров, которые принимает или возвращает функция (или сигнал, свойство, см. ниже). Это последовательность символов, каждый из которых определяет тип соответствующего параметра. Набор доступных типов довольно мощный. Например, есть более простые типы, такие как s для строки или u для 32-битного целого числа, но также и сложные типы, такие как as для массива строк или a(sb) для массива структур, состоящих из одной строки и одного логического значения. См. Спецификацию D-Bus, где приводится полное описание системы типов. Упомянутый выше метод ActivateSession принимает одну строку в качестве параметра (сигнатура параметра, следовательно, равна s) и ничего не возвращает (сигнатура возврата, следовательно, является пустой строкой). Конечно, сигнатура может быть намного сложнее, другие примеры см. ниже.

  • Сигнал - это еще один тип элемента, определяемый в объектной системе D-Bus. Как и у метода, у него есть сигнатура. Однако они служат разным целям. В то время как в вызове метода один клиент отправляет запрос к одному сервису, и этот сервис возвращает ответ клиенту, сигналы предназначены для общего уведомления узлов. Сервисы отправляют их, когда хотят сообщить одному или нескольким узлам на шине, что что-то произошло или изменилось. В отличие от вызовов методов и их ответов, они обычно транслируются по всей шине. В то время как вызовы/ответы методов используются для дуплексной связи один-к-одному, сигналы обычно используются для симплексной связи один-ко-многим (обратите внимание, что это не является обязательным требованием, их также можно использовать один-к-одному). Пример: systemd-logind передает сигнал SessionNew от своего объекта-менеджера каждый раз, когда пользователь входит в систему, и сигнал SessionRemoved каждый раз, когда пользователь выходит из системы.

  • Свойство - это третий тип элементов, определяемый в объектной системе D-Bus. Это похоже на концепцию свойств, известную в таких языках, как C#. Свойства также имеют сигнатуру. Они представляют собой переменные, предоставляемые объектом, которые могут быть прочитаны или изменены клиентами. Пример: systemd-logind предоставляет свойство Docked с сигнатурой b (логическое значение). Оно отражает, считает ли systemd-logind, что система в настоящее время находится в док-станции (применимо только к ноутбукам).

D-Bus определяет много различных концепций. Конечно, все эти новые концепции могут быть непонятными. Давайте посмотрим на них с другой точки зрения. Я предполагаю, что многие из читателей имеют представление о сегодняшних веб-технологиях, в частности о HTTP и REST. Попробуем сравнить концепцию HTTP-запроса с концепцией вызова метода D-Bus:

  • HTTP-запрос, который вы отправляете в определенной сети. Это может быть Интернет, ваша локальная сеть или корпоративный VPN. В зависимости от того, в какой сети вы отправляете запрос, вы сможете общаться с определённым набором серверов. Это мало чем отличается от шинной концепции D-Bus.

  • Затем в сети вы выбираете конкретный HTTP-сервер для общения. Это примерно сопоставимо с выбором сервиса на конкретной шине.

  • Затем на HTTP-сервере вы запрашиваете конкретный URL-адрес. Часть URL-адреса, определяющая путь (под которой я подразумеваю все после имени хоста сервера, вплоть до последнего /) очень похожа на путь к объекту D-Bus.

  • Файловая часть URL-адреса (под которой я подразумеваю все, что находится после последней косой черты, следующее за путём, который описан выше), определяет фактический вызов, который нужно сделать. В D-Bus это может быть сопоставлено с именем интерфейса и метода.

  • Наконец, параметры HTTP-вызова следуют в пути после знака ?, Они отображаются на сигнатуру вызова D-Bus.

Конечно, сравнение HTTP-запроса с вызовом метода D-Bus похоже на сравнение яблок и апельсинов. Тем не менее, я думаю, что полезно получить представление о том, что чему соответствует.

Из оболочки

Так много о концепциях и стоящей за ними серой теории. Давайте сделаем это увлекательным, давайте посмотрим, как это ощущается в реальной системе.

Некоторое время назад в systemd был включен инструмент busctl, который полезен для изучения и взаимодействия с объектной системой D-Bus. При вызове без параметров он покажет вам список всех узлов, подключенных к системной шине. (Вместо этого используйте --user, чтобы увидеть узлы вашей пользовательской шины):

$ busctlNAME                                       PID PROCESS         USER             CONNECTION    UNIT                      SESSION    DESCRIPTION:1.1                                         1 systemd         root             :1.1          -                         -          -:1.11                                      705 NetworkManager  root             :1.11         NetworkManager.service    -          -:1.14                                      744 gdm             root             :1.14         gdm.service               -          -:1.4                                       708 systemd-logind  root             :1.4          systemd-logind.service    -          -:1.7200                                  17563 busctl          lennart          :1.7200       session-1.scope           1          -[]org.freedesktop.NetworkManager             705 NetworkManager  root             :1.11         NetworkManager.service    -          -org.freedesktop.login1                     708 systemd-logind  root             :1.4          systemd-logind.service    -          -org.freedesktop.systemd1                     1 systemd         root             :1.1          -                         -          -org.gnome.DisplayManager                   744 gdm             root             :1.14         gdm.service               -          -[]

(Я немного сократил вывод, чтобы быть кратким).

Список начинается с узлов, подключенных в данный момент к шине. Они идентифицируются по именам, например ":1.11". В номенклатуре D-Bus они называются уникальными именами. По сути, каждый узел имеет уникальное имя, и они назначаются автоматически, когда узел подключается к шине. Если хотите, они очень похожи на IP-адрес. Вы заметите, что несколько узлов уже подключены, включая сам наш небольшой инструмент busctl, а также ряд системных сервисов. Затем в списке отображаются все текущие сервисы на шине, идентифицируемые по именам сервисов (как обсуждалось выше; чтобы отличить их от уникальных имен, они также называются хорошо известными именами). Во многих отношениях хорошо известные имена похожи на имена хостов DNS, то есть они являются более удобным способом ссылки на узел, но на нижнем уровне они просто сопоставляются с IP-адресом или, в этом сравнении, с уникальным именем. Подобно тому, как вы можете подключиться к хосту в Интернете либо по его имени, либо по его IP-адресу, вы также можете подключиться к узлу шины либо по его уникальному, либо по его общеизвестному имени. (Обратите внимание, что каждый узел может иметь сколько угодно хорошо известных имен, подобно тому, как IP-адрес может иметь несколько имен хостов, ссылающихся на него).

Ладно, это уже круто. Попробуйте сами, на своем локальном компьютере (все, что вам нужно, это современный дистрибутив на основе systemd).

Теперь перейдем к следующему шагу. Посмотрим, какие объекты на самом деле предлагает сервис org.freedesktop.login1:

$ busctl tree org.freedesktop.login1/org/freedesktop/login1  /org/freedesktop/login1/seat   /org/freedesktop/login1/seat/seat0   /org/freedesktop/login1/seat/self  /org/freedesktop/login1/session   /org/freedesktop/login1/session/_31   /org/freedesktop/login1/session/self  /org/freedesktop/login1/user    /org/freedesktop/login1/user/_1000    /org/freedesktop/login1/user/self

Красиво, не правда ли? Что на самом деле еще приятнее и чего не видно в выводе, так это то, что доступно полное автозавершение слов из командной строки: когда вы нажимаете TAB, оболочка автоматически заполняет имена служб за вас. Это замечательный инструмент для исследования объектов D-Bus!

В выводе показаны некоторые объекты, которые вы можете узнать из объяснений выше. А теперь пойдем дальше. Давайте посмотрим, какие интерфейсы, методы, сигналы и свойства фактически предоставляет один из этих объектов:

$ busctl introspect org.freedesktop.login1 /org/freedesktop/login1/session/_31NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGSorg.freedesktop.DBus.Introspectable interface -         -                                        -.Introspect                         method    -         s                                        -org.freedesktop.DBus.Peer           interface -         -                                        -.GetMachineId                       method    -         s                                        -.Ping                               method    -         -                                        -org.freedesktop.DBus.Properties     interface -         -                                        -.Get                                method    ss        v                                        -.GetAll                             method    s         a{sv}                                    -.Set                                method    ssv       -                                        -.PropertiesChanged                  signal    sa{sv}as  -                                        -org.freedesktop.login1.Session      interface -         -                                        -.Activate                           method    -         -                                        -.Kill                               method    si        -                                        -.Lock                               method    -         -                                        -.PauseDeviceComplete                method    uu        -                                        -.ReleaseControl                     method    -         -                                        -.ReleaseDevice                      method    uu        -                                        -.SetIdleHint                        method    b         -                                        -.TakeControl                        method    b         -                                        -.TakeDevice                         method    uu        hb                                       -.Terminate                          method    -         -                                        -.Unlock                             method    -         -                                        -.Active                             property  b         true                                     emits-change.Audit                              property  u         1                                        const.Class                              property  s         "user"                                   const.Desktop                            property  s         ""                                       const.Display                            property  s         ""                                       const.Id                                 property  s         "1"                                      const.IdleHint                           property  b         true                                     emits-change.IdleSinceHint                      property  t         1434494624206001                         emits-change.IdleSinceHintMonotonic             property  t         0                                        emits-change.Leader                             property  u         762                                      const.Name                               property  s         "lennart"                                const.Remote                             property  b         false                                    const.RemoteHost                         property  s         ""                                       const.RemoteUser                         property  s         ""                                       const.Scope                              property  s         "session-1.scope"                        const.Seat                               property  (so)      "seat0" "/org/freedesktop/login1/seat... const.Service                            property  s         "gdm-autologin"                          const.State                              property  s         "active"                                 -.TTY                                property  s         "/dev/tty1"                              const.Timestamp                          property  t         1434494630344367                         const.TimestampMonotonic                 property  t         34814579                                 const.Type                               property  s         "x11"                                    const.User                               property  (uo)      1000 "/org/freedesktop/login1/user/_1... const.VTNr                               property  u         1                                        const.Lock                               signal    -         -                                        -.PauseDevice                        signal    uus       -                                        -.ResumeDevice                       signal    uuh       -                                        -.Unlock                             signal    -         -                                        -

Как и раньше, команда busctl поддерживает автозавершение командной строки, поэтому и имя службы, и путь к объекту легко объединяются в оболочке простым нажатием TAB. Вывод показывает методы, свойства, сигналы одного из объектов сеанса, который в настоящее время доступен через systemd-logind. Есть раздел для каждого интерфейса, который известен объекту. Во втором столбце указывается тип члена. В третьем столбце отображается сигнатура члена. В случае методов, она описывает входные параметры. Четвертый столбец показывает возвращаемые параметры. Для свойств четвертый столбец кодирует их текущее значение.

Пока что мы только исследовали. Теперь сделаем следующий шаг: станем активными - вызовем метод:

# busctl call org.freedesktop.login1 /org/freedesktop/login1/session/_31 org.freedesktop.login1.Session Lock

Я не думаю, что мне нужно больше об этом упоминать, но в любом случае: снова доступно полное автозавершение командной строки. Третий аргумент - это имя интерфейса, четвертый - имя метода, оба могут быть легко заполнены нажатием TAB. В этом случае мы выбрали метод Lock, который активирует блокировку экрана для определенного сеанса. И оп, в тот момент, когда я нажал Enter в этой строке, у меня включилась блокировка экрана (это работает только на оконных менеджерах, которые правильно подключаются к systemd-logind. GNOME работает нормально, и KDE тоже должен работать).

Выбранный нами вызов метода Lock очень прост, поскольку он не принимает никаких параметров и не возвращает их. Конечно, для некоторых вызовов всё может быть сложнее. Вот еще один пример, на этот раз с использованием одного из вызовов на собственной шине systemd для запуска произвольного системного модуля:

# busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager StartUnit ss "cups.service" "replace"o "/org/freedesktop/systemd1/job/42684"

Этот вызов принимает две строки в качестве входных параметров, как описано в сигнатуре, которая следует за именем метода (как обычно, автозавершение командной строки помогает вам понять, как ввести параметры правильно). Следующие за сигнатурой два параметра - это просто две передаваемые строки. Таким образом, сигнатура указывает, какие параметры будут дальше. Вызов метода StartUnit systemd принимает имя модуля для запуска в качестве первого параметра и режим, в котором он запускается, в качестве второго. Вызов возвращает значение пути к объекту. Он кодируется так же, как входной параметр: сигнатура (только o для пути к объекту), за которой следует фактическое значение.

Конечно, некоторые параметры вызова методов могут быть намного сложнее, но с busctl их все относительно легко закодировать. См. подробности на странице руководства.

busctl поддерживает ряд других операций. Например, вы можете использовать его для мониторинга трафика D-Bus по мере его возникновения (включая создание файла .cap для использования с Wireshark!) Или вы можете установить или получить определенные свойства. Тем не менее, этот пост должен быть о sd-bus, а не busctl, поэтому давайте кратко остановимся здесь и позвольте мне направить вас на страницу руководства на случай, если вы хотите узнать больше об этом инструменте.

busctl (как и остальная часть системы) реализован с использованием API sd-bus. Таким образом, он раскрывает многие особенности самой sd-bus. Например, вы можете использовать его для подключения к удаленным или контейнерным шинам. Он поддерживает как kdbus, так и классический D-Bus, и многое другое!

sd-bus

Но хватит! Вернемся к теме, поговорим о самой sd-bus.

Набор API sd-bus в основном содержится в заголовочном файле sd-bus.h.

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

  • Поддерживает как kdbus, так и dbus1 в качестве серверной части.

  • Имеет высокоуровневую поддержку подключения к удаленным шинам по ssh и шинам локальных контейнеров ОС.

  • Мощная модель учетных данных для реализации аутентификации клиентов в сервисах. В настоящее время поддерживаются 34 отдельных поля, от PID клиента до контрольной группы или наборов возможностей.

  • Поддержка отслеживания жизненного цикла узлов для автоматического освобождения локальных объектов, когда все узлы, ссылающиеся на них, отключены.

  • Клиент строит эффективное дерево решений, чтобы определить, каким обработчикам доставить входящее сообщение шины.

  • Автоматически переводит ошибки D-Bus в ошибки стиля UNIX и обратно (хотя с потерями), чтобы обеспечить лучшую интеграцию D-Bus в низкоуровневые программы Linux.

  • Мощная, но легкая объектная модель для отображения локальных объектов на шине. При необходимости автоматически генерирует самоанализ.

В настоящее время API полностью не документирован, но мы работаем над завершением набора справочных страниц. Подробности смотрите на всех страницах, начинающихся с sd_bus_.

Вызов метода из Си с помощью sd-bus

Так много о библиотеке в целом. Вот пример подключения к шине и выполнения вызова метода:

#include <stdio.h>#include <stdlib.h>#include <systemd/sd-bus.h>int main(int argc, char *argv[]) {  sd_bus_error error = SD_BUS_ERROR_NULL;  sd_bus_message *m = NULL;  sd_bus *bus = NULL;  const char *path;  int r;  /* Connect to the system bus */  r = sd_bus_open_system(&bus);  if (r < 0) {    fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));    goto finish;  }  /* Issue the method call and store the respons message in m */  r = sd_bus_call_method(bus,                         "org.freedesktop.systemd1",           /* service to contact */                         "/org/freedesktop/systemd1",          /* object path */                         "org.freedesktop.systemd1.Manager",   /* interface name */                         "StartUnit",                          /* method name */                         &error,                               /* object to return error in */                         &m,                                   /* return message on success */                         "ss",                                 /* input signature */                         "cups.service",                       /* first argument */                         "replace");                           /* second argument */  if (r < 0) {    fprintf(stderr, "Failed to issue method call: %s\n", error.message);    goto finish;  }  /* Parse the response message */  r = sd_bus_message_read(m, "o", &path);  if (r < 0) {    fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));    goto finish;  }  printf("Queued service job as %s.\n", path);finish:  sd_bus_error_free(&error);  sd_bus_message_unref(m);  sd_bus_unref(bus);  return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;}

Сохраните этот пример как bus-client.c, а затем соберите его с помощью:

$ gcc bus-client.c -o bus-client `pkg-config --cflags --libs libsystemd`

Будет сгенерирован исполняемый файл bus-client, который вы теперь можете запустить. Обязательно запускайте его как root, поскольку доступ к методу StartUnit является привилегированным:

# ./bus-clientQueued service job as /org/freedesktop/systemd1/job/3586.

И это уже наш первый пример. Он показал, как мы вызывали метод на шине. Фактически вызов метода очень близок к инструменту командной строки busctl, который мы использовали ранее. Я надеюсь, что отрывок из кода не требует дополнительных пояснений. Он должен дать вам представление о том, как писать клиентов D-Bus с помощью sd-bus. Для получения дополнительной информации, пожалуйста, просмотрите заголовочный файл, страницу руководства или даже исходники sd-bus.

Реализация сервиса на Си с помощью sd-bus

Конечно, простой вызов одного метода - довольно упрощенный пример. Давайте посмотрим, как написать сервис шины. Мы напишем небольшой сервис калькулятора. Он предоставляет объект реализующий интерфейс, который предоставляет два метода: один для умножения двух 64-битных целых чисел со знаком, а другой для деления одного 64-битного целого числа со знаком на другое.

#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <systemd/sd-bus.h>static int method_multiply(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {  int64_t x, y;  int r;  /* Read the parameters */  r = sd_bus_message_read(m, "xx", &x, &y);  if (r < 0) {    fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));    return r;  }  /* Reply with the response */  return sd_bus_reply_method_return(m, "x", x * y);}static int method_divide(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {  int64_t x, y;  int r;  /* Read the parameters */  r = sd_bus_message_read(m, "xx", &x, &y);  if (r < 0) {    fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));    return r;  }  /* Return an error on division by zero */  if (y == 0) {    sd_bus_error_set_const(ret_error, "net.poettering.DivisionByZero", "Sorry, can't allow division by zero.");    return -EINVAL;  }  return sd_bus_reply_method_return(m, "x", x / y);}/* The vtable of our little object, implements the net.poettering.Calculator interface */static const sd_bus_vtable calculator_vtable[] = {  SD_BUS_VTABLE_START(0),  SD_BUS_METHOD("Multiply", "xx", "x", method_multiply, SD_BUS_VTABLE_UNPRIVILEGED),  SD_BUS_METHOD("Divide",   "xx", "x", method_divide,   SD_BUS_VTABLE_UNPRIVILEGED),  SD_BUS_VTABLE_END};int main(int argc, char *argv[]) {  sd_bus_slot *slot = NULL;  sd_bus *bus = NULL;  int r;  /* Connect to the user bus this time */  r = sd_bus_open_user(&bus);  if (r < 0) {    fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));    goto finish;  }  /* Install the object */  r = sd_bus_add_object_vtable(bus,                               &slot,                               "/net/poettering/Calculator",  /* object path */                               "net.poettering.Calculator",   /* interface name */                               calculator_vtable,                               NULL);  if (r < 0) {    fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));    goto finish;  }  /* Take a well-known service name so that clients can find us */  r = sd_bus_request_name(bus, "net.poettering.Calculator", 0);  if (r < 0) {    fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));    goto finish;  }  for (;;) {    /* Process requests */    r = sd_bus_process(bus, NULL);    if (r < 0) {      fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));      goto finish;    }    if (r > 0) /* we processed a request, try to process another one, right-away */      continue;    /* Wait for the next request to process */    r = sd_bus_wait(bus, (uint64_t) -1);    if (r < 0) {      fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));      goto finish;    }  }finish:  sd_bus_slot_unref(slot);  sd_bus_unref(bus);  return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;}

Сохраните этот пример как bus-service.c, а затем соберите его с помощью:

$ gcc bus-service.c -o bus-service `pkg-config --cflags --libs libsystemd`

А теперь запустим:

$ ./bus-service

В другом терминале попробуем с ним поговорить. Обратите внимание, что эта служба теперь находится на пользовательской шине, а не на системной шине, как раньше. Мы делаем это для простоты: доступ к сервисам на системной шине строго контролируется, поэтому непривилегированные клиенты не могут запрашивать привилегированные операции. Однако на пользовательской шине все проще: поскольку только процессы пользователя, владеющего шиной, могут подключиться, дальнейшее применение политики не усложнит этот пример. Поскольку служба находится на пользовательской шине, мы должны передать параметр --user в командной строке busctl. Начнем с просмотра дерева объектов сервиса.

$ busctl --user tree net.poettering.Calculator/net/poettering/Calculator

Как мы видим, в сервисе есть только один объект, что неудивительно, учитывая, что наш код выше зарегистрировал только один. Давайте посмотрим интерфейсы и члены, которые предоставляет этот объект:

$ busctl --user introspect net.poettering.Calculator /net/poettering/CalculatorNAME                                TYPE      SIGNATURE RESULT/VALUE FLAGSnet.poettering.Calculator           interface -         -            -.Divide                             method    xx        x            -.Multiply                           method    xx        x            -org.freedesktop.DBus.Introspectable interface -         -            -.Introspect                         method    -         s            -org.freedesktop.DBus.Peer           interface -         -            -.GetMachineId                       method    -         s            -.Ping                               method    -         -            -org.freedesktop.DBus.Properties     interface -         -            -.Get                                method    ss        v            -.GetAll                             method    s         a{sv}        -.Set                                method    ssv       -            -.PropertiesChanged                  signal    sa{sv}as  -            -

Как упоминалось выше, библиотека sd-bus автоматически добавила пару универсальных интерфейсов. Но первый интерфейс, который мы видим, на самом деле тот, который мы добавили! Он показывает наши два метода, и оба принимают xx (два 64-битных целых числа со знаком) в качестве входных параметров и возвращают один x. Отлично! Но правильно ли это работает?

$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Multiply xx 5 7x 35

Вау! Мы передали два целых числа 5 и 7, и служба фактически умножила их для нас и вернула одно целое число 35! Попробуем другой метод:

$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Divide xx 99 17x 5

Ух ты! Он может даже делать целочисленное деление! Фантастика! Но давайте обманем его делением на ноль:

$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Divide xx 43 0Sorry, can't allow division by zero.

Отлично! Он прекрасно это обнаружил и вернул чистую ошибку. Если вы посмотрите на приведенный выше пример исходного кода, вы увидите, насколько точно мы сгенерировали ошибку.

И это действительно всё, что у меня есть на сегодня. Конечно, примеры, которые я показал, короткие, и я не буду вдаваться в подробности того, что именно делает каждая строка. Однако этот пост должен быть кратким введением в D-Bus и sd-bus, и это уже слишком много для него...

Надеюсь, этот пост был вам полезен. Если вы заинтересованы в использовании sd-bus для своих собственных программ, я надеюсь, он поможет вам. Если у вас есть дополнительные вопросы, посмотрите (неполные) страницы руководства и спросите нас в IRC или в списке рассылки systemd. Если вам нужно больше примеров, взгляните на дерево исходных текстов systemd, все многочисленные шинные сервисы systemd широко используют sd-bus.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru