LINUX

Una buona conoscenza di D-BUS – Un meccanismo IPC in Linux

D-BUS è un meccanismo IPC (inter-process communication) che aiuta le applicazioni a comunicare tra loro. D-Bus (Desktop Bus) è un semplice IPC, sviluppato come parte di progetti freedesktop.

comprendere dbus IPC

Fornisce un livello di astrazione su varie applicazioni per esporre le loro funzionalità e capacità. Se si desidera utilizzare una determinata funzionalità di un’applicazione per fare in modo che un altro programma esegua un determinato compito, è possibile implementarlo facilmente rendendo consapevole il processo D-Bus.

Una volta che un’applicazione è conforme a D-Bus, non è necessario ricompilare o incorporare codice in essa per farla comunicare con altre applicazioni. Una cosa molto interessante di D-Bus è che aiuta gli sviluppatori a scrivere codice per qualsiasi applicazione abilitata per D-Bus in un linguaggio di loro scelta. Attualmente, i collegamenti D-Bus sono disponibili per C/C++, Glib, Java, Python, Perl, Ruby, ecc.

D-Bus è un sistema di bus di messaggi, un modo semplice per le applicazioni di comunicare tra loro, D-Bus fornisce un sistema e un demone di sessione.

Il demone di sistema viene avviato all’avvio del sistema e viene utilizzato principalmente per gli eventi hardware, mentre il demone di sessione viene avviato quando l’utente accede a un ambiente desktop e viene utilizzato per consentire alle applicazioni desktop di connettersi tra loro.

Nota: lo sviluppatore Dbus consiglia sempre di utilizzare la libreria di associazione DBus come dbus-glib o dbus-qt invece di utilizzare direttamente l’API DBus, hanno affermato che l’API DBus non è ancora bloccata e utilizza questa API diretta, il programmatore si iscrive per un po ‘di dolore, in la mia opinione, per comprendere chiaramente qualsiasi libreria di binding DBus, è un’ottima idea immergersi nella programmazione di basso livello DBus, nota che ciò che useremo qui è parte della banalità dell’API DBus.

D-Bus interno

D-Bus è un demone di servizio che viene eseguito in background. Utilizziamo demoni bus per interagire con le applicazioni e le loro funzionalità. Il daemon bus inoltra e riceve messaggi da e verso le applicazioni. Esistono due tipi di demoni bus: SessionBus e SystemBus.

Prima di iniziare a scrivere qualsiasi codice, ci sono alcuni termini con cui dovresti familiarizzare:

Connessione DBus:

DBusConnection è la struttura da utilizzare per aprire una connessione al daemon, il daemon del bus di sistema specificando DBUS_BUS_SYSTEM o il daemon del bus di sessione utilizzando DBUS_BUS_SESSION.

Messaggio DBus:

È semplicemente un messaggio tra due processi, tutta l’intercomunicazione DBus viene eseguita utilizzando DBus Message, questi messaggi possono avere i seguenti tipi, chiamate di metodo, ritorni di metodo, segnali ed errori. La struttura DBusMessage può eseguire parametri, aggiungendo al messaggio interi booleani, numeri reali, stringhe, array, ….

Sentiero:

È il percorso di un oggetto remoto, ad esempio /org/freedesktop/DBus.

Interfaccia:

È l’interfaccia di un particolare oggetto con cui parlare.

Segnale:

È un messaggio DBus per effettuare un’emissione di segnale.

Chiamata al metodo:

È un messaggio DBus utilizzato per invocare un metodo su un oggetto remoto.

Errore DBus:

DBusError è la struttura che contiene il codice di errore che si verifica chiamando un metodo DBus.

Ottenere una connessione bus:

DBusConnection *connection;

DBusError error;

dbus_error_init(&error); /* Initialize the error structure */

connection = dbus_bus_get(DBUS_BUS_SESSION,&error); /* Or DBUS_BUS_SYSTEM */

if ( dbus_error_is_set(&error) )

{

printf("Error connecting to the daemon bus: %s",error.message);

dbus_error_free(&error);

}

Per ora abbiamo appreso i concetti di base di DBus, successivamente impareremo i dettagli interni di un’applicazione basata su DBus attraverso esempi.

Esempio 1: prenotazione di un nome bus

Giusto per familiarizzare con la programmazione DBus, in questo esempio vedremo come possiamo riservare un nome di bus per la nostra piccola applicazione. Esiste una certa restrizione che DBus applica ai nomi dei bus, sono una stringa UTF-8 valida e devono avere almeno un “.” separando i nomi degli elementi, ogni elemento deve contenere almeno un carattere, ad esempio “org.freedesktop”. , per un elenco completo, leggere la sezione Specifica nome bus DBus.

#include <stdio.h>

#include <dbus/dbus.h>

int main()

{

DBusConnection *connection;

DBusError error;

 

char *name = "org.share.linux";

dbus_error_init(&error);

connection = dbus_bus_get(DBUS_BUS_SESSION, &error);

if ( dbus_error_is_set(&error) )

{

printf("Error connecting to the daemon bus: %s",error.message);

dbus_error_free(&error);

return 1;

}

dbus_bool_t ret = dbus_bus_name_has_owner(connection,name,&error);

if ( dbus_error_is_set(&error) )

{

dbus_error_free(&error);

printf("DBus Error: %sn",error.message);

return 1;

}

if ( ret == FALSE )

{

printf("Bus name %s doesn't have an owner, reserving it...n",name);

int request_name_reply =

dbus_bus_request_name( connection,name, DBUS_NAME_FLAG_DO_NOT_QUEUE,

&error);

if ( dbus_error_is_set(&error) )

{

dbus_error_free(&error);

printf("Error requesting a bus name: %sn",error.message);

return 1;

}

 

if ( request_name_reply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER )

{

printf("Bus name %s Successfully reserved!n",name);

return 0;

}

else

{

printf("Failed to reserve name %sn",name);

return 1;

}

}

else

/*

if ret of method dbus_bus_name_has_owner is TRUE, then this is useful for

detecting if your application is already running and had reserved a bus name

unless somebody stole this name from you, so better to choose a correct bus

name

*/

{

printf("%s is already reservedn", name);

return 1;

}

return 0;

}

Abbiamo usato il flag DBUS_NAME_FLAG_DO_NOT_QUEUE, DBus non ci metterà in coda se il nome del bus che vogliamo prenotare è già in uso. Per un elenco completo dei flag dbus_bus_request_name e del codice restituito, vedere l’API DBus. Un nome di bus richiesto può sempre essere rilasciato utilizzando dbus_bus_release_name.

Per compilare il codice sopra deve essere installato il pacchetto di sviluppo DBus, a seconda della tua distribuzione il nome di questo pacchetto può essere diverso ma dovrebbe essere qualcosa come libdbus-dev (Su un sistema Slackware tutto il pacchetto viene fornito con i file Development). Quindi compilare il codice con il seguente comando:

gcc `pkg-config --libs --cflags dbus-1` example1.c -o example1

pkg-config tenta di trovare il file dbus-1.pc, questo file si trova solitamente con altri in /usr/lib/pkgconfig e tali file contengono informazioni sulle librerie a cui collegarsi.

Esempio 2: collegamento di due applicazioni desktop

In questo esempio, utilizzeremo DBus per connettere due applicazioni desktop, una ascolta i messaggi DBus e l’altra invia messaggi DBus, ma prima di iniziare, il programma listener non deve solo avviarsi ed uscire, ma deve attendere gli eventi, quindi abbiamo per trovare un modo per organizzare gli eventi inviati nel nostro programma, una soluzione semplice per questo è utilizzare il ciclo di eventi principale di glib, quando lo usiamo possiamo mantenere il nostro programma in modalità sleep fino a quando gli eventi non vengono ricevuti, si verifica un altro problema è che come possiamo integrare la nostra connessione bus con glib main event loop, è qui che entra in gioco dbus-glib, quindi il nostro piccolo programma dipenderà anche da dbus-glib per una singola chiamata, dbus_connection_setup_with_g_main, questa chiamata integra glib main loop e bus events Bus.

Qui sorge una domanda, se vogliamo usare solo DBus, come possiamo evitare di usare il suo legame glib, la risposta non è semplice, prima dobbiamo scrivere i nostri eventi di loop e integrarli con eventi di bus, una buona cosa. l’inizio è guardare i sorgenti di DBus, dato che hanno del codice utile in dbus/dbus-mainloop, ma per semplificare il nostro lavoro useremo dbus-glib.

ascolta.c

In questo programma useremo dbus_bus_add_match(DbusConnection *,const char *rule, DBusError *) per aggiungere una corrispondenza per i messaggi che vogliamo ricevere, la stringa della regola ha un formato specifico, vedi Regola di corrispondenza DBus per tutti i dettagli.

#include <stdio.h>

#include <dbus/dbus.h>

#include <dbus/dbus-glib.h>

#include <glib.h>

static DBusHandlerResult

dbus_filter (DBusConnection *connection, DBusMessage *message, void *user_data)

{

 

if ( dbus_message_is_signal(message,"org.share.linux","Customize" ) )

{

printf("Message cutomize receivedn");

return DBUS_HANDLER_RESULT_HANDLED;

}

if ( dbus_message_is_signal(message,"org.share.linux","Quit" ) )

{

printf("Message quit receivedn");

GMainLoop *loop = (GMainLoop*) user_data;

g_main_loop_quit(loop);

return DBUS_HANDLER_RESULT_HANDLED;

}

return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

}

int main()

{

DBusConnection *connection;

DBusError error;

/* glib main loop */

GMainLoop *loop;

loop = g_main_loop_new(NULL,FALSE);

dbus_error_init(&error);

connection = dbus_bus_get(DBUS_BUS_SESSION, &error);

if ( dbus_error_is_set(&error) )

{

printf("Error connecting to the daemon bus: %s",error.message);

dbus_error_free(&error);

return 1;

}

dbus_bus_add_match (connection,

"type="signal",interface="org.share.linux"",NULL);

dbus_connection_add_filter (connection, dbus_filter, loop, NULL);

/* dbus-glib call */

dbus_connection_setup_with_g_main(connection,NULL);

/* run glib main loop */

g_main_loop_run(loop);

return 0;

}

invia.c

#include <stdio.h>

#include <dbus/dbus.h>

static void

send_config(DBusConnection *connection)

{

DBusMessage *message;

message = dbus_message_new_signal ("/org/share/linux",

"org.share.linux",

"Config");

/* Send the signal */

dbus_connection_send (connection, message, NULL);

dbus_message_unref (message);

}

static void

send_quit (DBusConnection *connection)

{

DBusMessage *message;

message = dbus_message_new_signal ("/org/share/linux",

"org.share.linux",

"Quit");

/* Send the signal */

dbus_connection_send (connection, message, NULL);

dbus_message_unref (message);

}

int

main (int argc, char **argv)

{

DBusConnection *connection;

DBusError error;

dbus_error_init (&error);

connection = dbus_bus_get (DBUS_BUS_SESSION, &error);

if (!connection)

{

printf ("Failed to connect to the D-BUS daemon: %s", error.message);

dbus_error_free (&error);

return 1;

}

if ( argc == 1 )

{

return 0;

}

 

int i;

for ( i = 1; i < argc; i++)

{

if (!strcmp(argv[i],"-c") )

{

send_config(connection);

}

else if ( !strcmp(argv[i],"-q") )

{

send_quit(connection);

}

}

return 0;

}

Per compilare, eseguire i seguenti comandi:

gcc `pkg-config --libs --cflags dbus-1 glib-2.0 dbus-glib-1` listen.c -o listen

gcc `pkg-config --libs --cflags dbus-1` send.c -o send

Esempio 3: Servizi DBus

Il message bus può avviare applicazioni (servizi) per conto di altre applicazioni, l’applicazione chiede al DBus di avviare un servizio con il suo nome, solitamente il nome dovrebbe essere noto, come org.freedesktop.TextEditor.

Affinché DBus trovi l’eseguibile corrispondente a un determinato nome, il demone del bus cerca i file di descrizione del servizio che di solito sono installati in /usr/share/dbus-1/services e hanno .service nell’estensione del nome (tutte le distribuzioni Linux) . che so di utilizzare questo prefisso per installare i file di servizio dbus), come file di servizio di esempio.

File di servizio DBus di esempio:

[D-BUS Service]

Name=org.share.linux

Exec=path to the executable.

Scriveremo due programmi, uno è il servizio che vogliamo avviare, l’altro è l’applicazione che attiva questo servizio

share-linux-service-example.c

#include <stdio.h>

#include <dbus/dbus.h>

int main()

{

DBusConnection *connection;

DBusError error;

 

dbus_error_init(&error);

connection = dbus_bus_get(DBUS_BUS_STARTER, &error); /* DBUS_BUS_STARTER is

the bus that started us */

/* Do something here to make sure that the application was successfully

started by DBus

* Example could be something like

* FILE *tmp;

* tmp = fopen("/tmp/share-linux-service.result", "w");

* fprintf(tmp,"share-linux service was started successfully");

* fclose(tmp);

* /

 

/* After that you have the service up, so you can do whetever you like */

dbus_connection_unref(connection);

 

return 0;

}

Compila questo esempio con l’argomento dbus-1 in pkg-config, devi installare il file di servizio in /usr/share/dbus-1/service, chiamarlo org.share.linux e modificarlo

Exec percorso in cui si trova il file binario del servizio di esempio.

start-service.c

#include <stdio.h>

#include <dbus/dbus.h>int main()

{

DBusConnection *connection;

DBusError error;

DBusMessage *message;

 

const char *service_name = "org.share.linux";

dbus_uint32_t flag; /* Currently this is not used by DBus, they say it is for

futur expansion*/

dbus_bool_t result;

 

dbus_error_init(&error);

 

connection = dbus_bus_get(DBUS_BUS_SESSION, &error);

 

if ( dbus_error_is_set(&error) )

{

printf("Error getting dbus connection: %sn",error.message);

dbus_error_free(&error);

dbus_connection_unref(connection);

return 0;

}

 

message = dbus_message_new_method_call("org.freedesktop.DBus",

"/org/freedesktop/DBus",

"org.freedesktop.DBus",

"StartServiceByName");

 

if ( !message )

{

printf("Error creating DBus messagen");

dbus_connection_unref(connection);

return 0;

}

 

dbus_message_set_no_reply(message, TRUE); /* We don't want to receive a reply

*/

 

/* Append the argument to the message, must ends with DBUS_TYPE_UINT32 */

dbus_message_append_args(message,

DBUS_TYPE_STRING,

&service_name,

DBUS_TYPE_UINT32,

&flag,

DBUS_TYPE_INVALID);

 

result = dbus_connection_send(connection, message, NULL);

 

 

if ( result == TRUE )

{

printf("Successfully activating the %s servicen",service_name);

}

else

{

printf("Failed to activate the %s servicen",service_name);

}

dbus_message_unref(message);

dbus_connection_unref(connection);

return 0;

}

Risoluzione dei problemi D-BUS

Per eseguire il debug di applicazioni basate su D-Bus, possiamo utilizzare DBus-monitor per esaminare gli eventi per l’analisi. In alternativa, possiamo utilizzare alcuni degli strumenti di debug facilmente disponibili, come il debugger D-Feet D-Bus (scritto da John Palmeri).

Conclusione

Nel mondo delle applicazioni di oggi, la maggior parte delle applicazioni GNOME e KDE sono dotate di supporto per l’interfaccia DBus. Rende più facile per le applicazioni comunicare tra loro e rimuove l’attività di ordine superiore di ricompilare ciascuna applicazione per renderla compatibile con un’altra.

Related Articles

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Back to top button
Close