D-Bus

редактировать
D-Bus
Разработчик (и) Red Hat
Первоначальный выпускНоябрь 2006 г.; 13 лет назад (2006-11)
Стабильный выпуск 1.12.20 / 2 июля 2020 г.; 3 месяца назад (02.07.2020)
Предварительный выпуск 1.13.18 / 2 июля 2020 г.; 3 месяца назад (02.07.2020)
Репозиторий Редактировать в Викиданных
Написано наC
Операционная система Кросс-платформенный
Тип
Лицензия GPLv2 + или AFL 2.1
Веб-сайтwww.freedesktop.org / wiki / Software / dbus

В вычислениях, D-Bus (сокращение от «Desktop Bus ") - это программная шина, межпроцессное взаимодействие (IPC) и механизм удаленного вызова процедур (RPC), который обеспечивает связь между несколькими процессами ,, работающими одновременно на одной машине. D-Bus был разработан как часть проекта freedesktop.org, инициированного Havoc Pennington из Red Hat для стандартизации услуг, предоставляемых Linux среды рабочего стола, такие как GNOME и KDE.

В рамках проекта freedesktop.org также была разработана бесплатная программная библиотека с открытым исходным кодом, которая называется libdbus, как эталонная реализация спецификации. Эту библиотеку не следует путать с самим D-Bus, поскольку также существуют другие реализации спецификации D-Bus, такие как GDBus (GNOME), QtDBus (Qt / KDE), dbus-java и sd- шина (часть systemd ).

Содержание

  • 1 Обзор
  • 2 Спецификация D-Bus
    • 2.1 Модель шины
    • 2.2 Объектная модель
    • 2.3 Модель связи
  • 3 Внутреннее устройство
  • 4 История и внедрение
  • 5 Реализации
    • 5.1 libdbus
    • 5.2 GDBus
    • 5.3 QtDBus
    • 5.4 sd-bus
    • 5.5 libnih-dbus
    • 5.6 kdbus
    • 5.7 Привязки языков
  • 6 См. Также
  • 7 Ссылки
  • 8 Внешние ссылки

Обзор

D-Bus - это механизм IPC, изначально разработанный для замены программного компонента используемых систем связи с помощью GNOME и KDE Linux среды рабочего стола (CORBA и DCOP соответственно). Компоненты этого рабочего стола среды обычно распределяются по множеству процессов, каждый из которых предоставляет только несколько - обычно одну - сервисов. Эти сервисы могут использоваться d обычными клиентскими приложениями или другими компонентами среды рабочего стола для выполнения своих задач.

Процессы без D-Bus Процессы без D-Bus Процессы с D-Bus Те же процессы с D-Bus Большие группы взаимодействующих процессов требуют плотной сети отдельных каналов связи (с использованием методов IPC «один-к-одному») между ними. D-Bus упрощает требования IPC с помощью одного единого общего канала.

Из-за большого количества задействованных процессов - добавления процессов, предоставляющих услуги, и клиентов, получающих к ним доступ, - установление связи IPC «один-к-одному» между всеми ними становится неэффективный и довольно ненадежный подход. Вместо этого D-Bus предоставляет абстракцию software-bus , которая собирает все коммуникации между группой процессов по одному общему виртуальному каналу. Процессы, подключенные к шине, не знают, как это реализовано внутри, но спецификация D-Bus гарантирует, что все процессы, подключенные к шине, могут общаться друг с другом через нее.

Среды рабочего стола Linux используют возможности D-Bus, создавая экземпляры не одной шины, а множества:

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

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

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

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

спецификацией D-Bus

Модель шины

Каждое соединение с шиной идентифицируется в контексте D-Bus по так называемому имени шины. Имя шины состоит из двух или более разделенных точками строк букв, цифр, тире и подчеркиваний. Пример действительного имени шины: org.freedesktop.NetworkManager.

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

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

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

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

Объектная модель

Из-за своей первоначальной концепции как заменив несколько компонентно-ориентированных систем связи, D-Bus разделяет со своими предшественниками объектную модель, в которой выражается семантика связи между клиентами и службами. Термины, используемые в объектной модели D-Bus, имитируют термины, используемые некоторыми объектно-ориентированными языками программирования. Это не означает, что D-Bus каким-то образом ограничен языками ООП - на самом деле, наиболее часто используемая реализация (libdbus) написана на C, языке процедурного программирования..

Просмотр существующих имен шин, объектов, интерфейсов, методов и сигналов в шине D-Bus с помощью D-Feet

В D-Bus процесс предлагает свои услуги, открывая объекты. У этих объектов есть методы, которые можно вызывать, и сигналы, которые объект может испускать. Методы и сигналы вместе называются членами объекта. Любой клиент, подключенный к шине, может взаимодействовать с объектом, используя его методы, делая запросы или отдавая команду объекту на выполнение действий. Например, объект, представляющий службу времени, может быть запрошен клиентом с помощью метода, который возвращает текущую дату и время. Клиент также может прослушивать сигналы, которые излучает объект, когда его состояние изменяется из-за определенных событий, обычно связанных с базовой службой. Примером может служить служба, управляющая аппаратными устройствами, такими как USB или сетевые драйверы, сигнализирует о событии «добавлено новое аппаратное устройство». Клиенты должны проинструктировать шину о том, что они заинтересованы в получении определенных сигналов от определенного объекта, поскольку шина D-Bus передает сигналы только тем процессам, у которых зарегистрирован интерес к ним.

Процесс, подключенный к D- Bus bus может запросить экспорт любого количества объектов D-Bus. Каждый объект идентифицируется путем к объекту, строкой чисел, букв и подчеркиваний, разделенных и предваренных символом косой черты, который называется так из-за их сходства с путями файловой системы Unix. Путь к объекту выбирается запрашивающим процессом и должен быть уникальным в контексте данного шинного соединения. Пример допустимого пути к объекту: / org / kde / kspread / sheet / 3 / cells / 4/5. Однако не принуждают - но и не препятствуют - формировать иерархии внутри путей к объектам. Конкретное соглашение об именах для объектов службы полностью зависит от разработчиков такой службы, но многие разработчики предпочитают пространство имен, используя зарезервированное доменное имя проекта в качестве префикса. (например, /org/kde).

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

Члены - методы и сигналы - которые можно использовать с объектом, определяются интерфейсом. Интерфейс - это набор объявлений методов (включая параметры передачи и возврата) и сигналов (включая параметры), идентифицируемых разделенными точками именами, напоминающими нотацию интерфейсов языка Java. Пример допустимого имени интерфейса: org.freedesktop.Introspectable. Несмотря на их схожесть, имена интерфейсов и имена шин не должны ошибаться. Объект D-Bus может реализовывать несколько интерфейсов, но, по крайней мере, должен реализовывать один, обеспечивая поддержку всех методов и сигналов, определенных им. Комбинация всех интерфейсов, реализованных объектом, называется типом объекта.

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

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

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

Спецификация D-Bus определяет ряд операций административной шины (называемых "автобусными службами") ") для выполнения с использованием объекта / org / freedesktop / DBus, который находится в имени шины org.freedesktop.DBus. Каждая шина резервирует это специальное имя шины для себя и управляет любыми запросами, сделанными специально для этой комбинации имени шины и пути объекта. Административные операции, обеспечиваемые шиной, определяются интерфейсом объекта org.freedesktop.DBus. Эти операции используются, например, для предоставления информации о состоянии шины или для управления запросом и выдачей дополнительных хорошо известных имен шин.

Модель связи

Была разработана D-Bus в качестве общей высокоуровневой системы межпроцессного взаимодействия. Для достижения этих целей связь D-Bus основана на обмене сообщениями между процессами, а не на «сырых байтах». Сообщения D-Bus - это дискретные элементы высокого уровня, которые процесс может отправить через шину другому подключенному процессу. Сообщения имеют четко определенную структуру (определены даже типы данных, переносимых в их полезной нагрузке), что позволяет шине проверять их и отклонять любое неверно сформированное сообщение. В этом отношении D-Bus ближе к механизму RPC, чем к классическому механизму IPC, со своей собственной системой определения типов и собственным маршалингом.

Пример однозначного запроса обмен сообщениями ответа для вызова метода через D-Bus. Здесь клиентский процесс вызывает метод SetFoo () объекта / org / example / object1 из служебного процесса с именем org.example.foo (или : 1.14) в шина.

Шина поддерживает два режима обмена сообщениями между клиентом и процессом службы:

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

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

Спецификация D-Bus определяет проводной протокол : как создавать сообщения D-Bus для обмена между процессами в рамках соединения D-Bus. Однако он не определяет базовый метод транспорта для доставки этих сообщений.

Внутреннее устройство

Большинство существующих реализаций D-Bus следуют архитектуре эталонной реализации. Эта архитектура состоит из двух основных компонентов:

  • двухточечной связи библиотеки, которая реализует проводной протокол D-Bus для обмена сообщениями между двумя процессами. В эталонной реализации это библиотека libdbus . В других реализациях libdbus может быть обернут другой библиотекой более высокого уровня, языковой привязкой или полностью заменен другой автономной реализацией, которая служит той же цели. Эта библиотека поддерживает связь только один-к-одному между двумя процессами.
  • A dbus-daemon процесс, действующий как демон шины сообщений D-Bus. Каждый процесс, подключенный к шине, поддерживает с ним одно соединение D-Bus. специальный процесс-демон, который играет роль шины и к которому остальные процессы подключаются с помощью любой точки D-Bus. библиотека точечных коммуникаций. Этот процесс также известен как демон шины сообщений, поскольку он отвечает за маршрутизацию сообщений от любого процесса, подключенного к шине, к другому. В эталонной реализации эту роль выполняет dbus-daemon, который сам построен поверх libdbus. Другой реализацией демона шины сообщений является dbus-broker, который построен на основе sd-bus .
Процессы A и B имеют однозначное соединение D-Bus между ними через сокет домена Unix Процессы A и B имеют взаимно однозначное Соединение D-Bus с использованием libdbus через сокет домена Unix. Они могут использовать его для прямого обмена сообщениями. В этом сценарии имена шины не требуются. Процесс A и B имеют оба -one соединение D-Bus с процессом dbus-daemon через сокет домена Unix Процессы A и B оба подключены к dbus-daemon с помощью libdbus через сокет домена Unix. Они могут обмениваться сообщениями, отправляя их процессу шины сообщений, который, в свою очередь, доставляет сообщения соответствующему процессу. В этом сценарии имена шин являются обязательными для идентификации процесса назначения.

Библиотека libdbus (или ее эквивалент) внутри использует собственный низкоуровневый механизм IPC для передачи требуемых сообщений D-Bus между двумя процессами в обоих процессах. концы соединения D-Bus. Спецификация D-Bus не требует, какие конкретные транспортные механизмы IPC должны быть доступны для использования, поскольку именно коммуникационная библиотека решает, какие транспортные методы она поддерживает. Например, в Linux и Unix-подобных операционных системах libdbus обычно использует доменные сокеты Unix в качестве основного метода транспорта, но также поддерживает TCP-сокеты.

Коммуникационные библиотеки обоих процессов должны согласовать выбранный способ транспортировки, а также конкретный канал, используемый для их связи. Эта информация определяется тем, что D-Bus называет адресом. Доменный сокет Unix - это объекты файловой системы, и поэтому они могут быть идентифицированы по имени файла, поэтому допустимый адрес будет unix: path = / tmp /.hiddensocket. Оба процесса должны передать один и тот же адрес своим соответствующим коммуникационным библиотекам, чтобы установить между ними соединение D-Bus. Адрес также может предоставлять дополнительные данные для библиотеки связи в виде разделенных запятыми пар ключ = значение. Таким образом, например, он может предоставить информацию аутентификации для определенного типа соединения, которое его поддерживает.

Когда демон шины сообщений, например dbus-daemon, используется для реализации шины D-Bus, все процессы, которые хотят подключиться к шине, должны знать адрес шины, адрес, по которому процесс может установить соединение D-Bus с процессом центральной шины сообщений. В этом сценарии демон шины сообщений выбирает адрес шины, а остальные процессы должны передать это значение в свои соответствующие libdbus или эквивалентные библиотеки. dbus-daemon определяет разные адреса шины для каждого экземпляра шины, который он предоставляет. Эти адреса определены в файлах конфигурации демона.

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

dbus-daemon улучшает набор функций, уже предоставленный D- Сама шина с дополнительным функционалом. Например, активация службы позволяет автоматически запускать службы при необходимости - когда первый запрос к любому имени шины такой службы поступает на демон шины сообщений. Таким образом, служебные процессы не нужно запускать во время инициализации системы или этапа инициализации пользователя, а также потреблять память или другие ресурсы, когда они не используются. Первоначально эта функция была реализована с помощью помощников setuid, но в настоящее время она также может быть предоставлена ​​структурой активации служб systemd. Активация службы - важная функция, которая облегчает управление жизненным циклом процесса службы (например, когда компонент рабочего стола должен запускаться или останавливаться).

История и внедрение

D-Bus был запущен в 2002 г. Авторы Havoc Pennington, Alex Larsson (Red Hat ) и Андерс Карлссон. Версия 1.0, которая считается API стабильной, была выпущена в ноябре 2006 года.

dbus-daemon играет значительную роль в современных графических средах Linux ..

На него сильно влияют Система DCOP, используемая версиями 2 и 3 из KDE, D-Bus заменила DCOP в версии KDE 4. Реализация D-Bus поддерживает большинство операционных систем POSIX, и существует порт для Windows. Он используется Qt 4 и GNOME. В GNOME он постепенно заменил большую часть более раннего механизма Bonobo. Он также используется Xfce.

. Одним из первых последователей был (в настоящее время не рекомендуется) Hardware Abstraction Layer. HAL использовал D-Bus для экспорта информации об оборудовании, которое было добавлено на компьютер или удалено с него.

Использование D-Bus неуклонно расширяется за пределы первоначальной области настольных сред, чтобы охватить все большее количество систем. Сервисы. Например, сетевой демон NetworkManager, стек Bluetooth BlueZ и звуковой сервер PulseAudio используют D-Bus для предоставления части или всех своих услуг. systemd использует проводной протокол D-Bus для связи между systemctl и systemd, а также продвигает традиционные системные демоны в службы D-Bus, такие как logind. Еще один активный пользователь D-Bus - Polkit, демон полномочий политик которого реализован как служба, подключенная к системной шине.

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

Реализации

libdbus

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

GDBus

GDBus - это реализация D-Bus на основе потоков GIO, включенных в GLib, с целью использования GTK + и GNOME. GDBus - это не оболочка libdbus, а полная и независимая реализация спецификации и протокола D-Bus. MATE Desktop и Xfce (версия 4.14), которые также основаны на GTK + 3, также используйте GDBus.

QtDBus

QtDBus - это реализация D-Bus, включенная в библиотеку Qt начиная с ее версии 4.2. Этот компонент используется приложениями, библиотеками и компонентами KDE для доступа к службам D-Bus, доступным в системе.

sd-bus

В 2013 году проект systemd переписал libdbus, пытаясь упростить код, но это также привело к значительному увеличению общего D- Производительность автобуса. В предварительных тестах BMW обнаружил, что библиотека D-Bus systemd повысила производительность на 360%. В версии 221 systemd sd-bus API был объявлен стабильным.

libnih-dbus

Проект libnih предоставляет облегченный «стандартная библиотека» C поддерживает D-Bus. Кроме того, он имеет хорошую поддержку кросс-компиляции.

kdbus

kdbus реализован как драйвер символьного устройства. Все коммуникации между процессами происходят через узлы специальных символьных устройств в / dev / kdbus(см. devfs ).

kdbus был проектом, который был нацелен на повторную реализацию D-Bus как опосредованного ядром однорангового узла. to-peer механизм межпроцессного взаимодействия. Помимо улучшений производительности, kdbus будет иметь преимущества, связанные с другими функциями ядра Linux, такими как пространства имен и аудит, безопасность от посредничество ядра, закрытие условий гонки и разрешение использования D-Bus во время загрузки и завершения работы (при необходимости для systemd). Включение kdbus в ядро ​​Linux оказалось спорным и было отклонено в пользу более общего -процессное взаимодействие.

Языковые привязки

Было разработано несколько языков программирования привязок для D-Bus, например, для Java, C# и Ruby.

См. Также

  • Портал бесплатного программного обеспечения с открытым исходным кодом

Ссылки

Внешние ссылки

Последняя правка сделана 2021-05-16 08:09:13
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте