在发出 dbus-send 命令后,如何使用 C 调用方法?

Posted

技术标签:

【中文标题】在发出 dbus-send 命令后,如何使用 C 调用方法?【英文标题】:How does a method get called using C, after the dbus-send command is issued? 【发布时间】:2015-12-04 02:13:25 【问题描述】:

我正在学习如何通过 GLib 在 C 上使用 D-Bus。到目前为止,我已经创建了一个调用我的应用程序的 D-Bus 服务,并且在使用“dbus-send”命令后我得到了响应。我有两个文件,一个是 D-Bus 代码,一个是要调用的函数。 'test_method_start' 函数让我们知道它已被成功调用,并创建了一个新线程。第二个函数告诉我们我们正在停止,并退出线程。

我显然遗漏了一些东西,因为我没有看到函数调用的结果。谁能告诉我哪里出错了?我指的是here的例子。

这里是sn-ps的代码:

文件1.c:

void test_method_start()

    printf("Test method started\n")``;
    //syslog(LOG_NOTICE, "Test method started\n");
    if (!(pthread_create(&socketServerThread, NULL, 
       socketServerLoop, &socketServerParam)))
    
        printf("Socket Server thread created successfully\n");
    
    else
        fprintf(stderr, "Error creating Socket Server thread\n");
    pthread_exit(NULL);


void test_method_stop()

    printf("Test method ended\n");
    pthread_exit(NULL);

文件2.c:

/*
* dbusClient
*/

/** Headers **/

#include "dbusClient.h"
#include <glib.h>
#include <gio/gio.h>
#include <gio/gioerror.h>
#include <gio/gdbuserror.h>
#include <stdlib.h>
#include <stdio.h>


/** Function Predeclarations    **/

/** Globals **/

/**  The service name on the bus. **/
static const gchar service[] = "org.test.DBusClient";

/** The object we publish on the bus.   **/
static const gchar object_path[] = "/org/test/DBusObject";

/** Introspection data for the one object, in the internal form.    **/
static GDBusNodeInfo *introspection_data = NULL;

/** Introspection data for the one object in XML form   **/

static const gchar introspection_xml[] =
            "<node>"
            "  <interface name='org.test.DBusClientInterface'>"
            "    <method name='test_method_start'>"
            "      <arg type='s' name='message' direction='in'/>"
            "      <arg type='s' name='response' direction='out'/>"
            "    </method>"
            "    <method name='test_method_stop'>"
            "      <arg type='s' name='message' direction='in'/>"
            "      <arg type='s' name='response' direction='out'/>"
            "    </method>"
            "  </interface>"
            "</node>";


/** Object Callbacks    **/

/*  Handle a request for a property */

static GVariant *handle_get_property (GDBusConnection  *connection,
                     const gchar      *sender,
                     const gchar      *object_path,
                     const gchar      *interface_name,
                     const gchar      *property_name,
                     GError          **error,
                     gpointer          user_data)

    printf("handle_get_property\n");
/*  Print an optional log message   */
#ifdef VERBOSE
  fprintf (stderr, "[server 0] "
  "handle_get_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n",
  connection, sender, object_path, interface_name, property_name,
           user_data);
#endif

/*  We currently don't have any properties, 
so this should be an error. */
g_set_error (error,
               G_IO_ERROR,
               G_IO_ERROR_FAILED,
               "[server 0] Invalid property '%s'",
               property_name);
// And we're done
return NULL;

 // handle_get_property

/*  Handle a call to a method   */
static void handle_method_call (GDBusConnection       *connection,
                    const gchar           *sender,
                    const gchar           *object_path,
                    const gchar           *interface_name,
                    const gchar           *method_name,
                    GVariant              *parameters,
                    GDBusMethodInvocation *invocation,
                    gpointer               user_data)

    printf("handle_method_call\n");
#ifdef VERBOSE
  gchar *paramstr = g_variant_print (parameters, TRUE);
  fprintf (stderr, "[server 0] "
"handle_method_call (%p,\"%s\",\"%s\",\"%s\",\"%s",
\"\",invocation),%p)\n",
          connection, sender, object_path, interface_name, method_name,
           paramstr, user_data);
  g_free (paramstr);
#endif

/*  Default: No such method */

    if (g_strcmp0 (method_name, "test_method_start") == 0)
    
        const gchar *greeting;

        g_variant_get (parameters, "(&s)", &greeting);

        if (g_strcmp0 (greeting, "Return Unregistered") == 0)
        
            g_dbus_method_invocation_return_error (invocation,
                   G_IO_ERROR,
                   G_IO_ERROR_FAILED_HANDLED,
                   "As requested, here's a GError not registered 
                   (G_IO_ERROR_FAILED_HANDLED)");
        
        else if (g_strcmp0 (greeting, "Return Registered") == 0)
        
            g_dbus_method_invocation_return_error (invocation,
                   G_DBUS_ERROR,
                   G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
            "As requested, here's a GError that is 
             registered
             (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
        
        else if (g_strcmp0 (greeting, "Return Raw") == 0)
        
            g_dbus_method_invocation_return_dbus_error (invocation,
            "org.gtk.GDBus.SomeErrorName",
            "As requested, here's a raw D-Bus error");
        
        else
        
            gchar *response;
            response = g_strdup_printf ("You greeted me with '%s'. 
            Thanks!", greeting);
            g_dbus_method_invocation_return_value 
            (invocation,               
            g_variant_new ("(s)", response));
            g_free (response);
        
      
      else if (g_strcmp0 (method_name, "test_method_stop") == 0)
      
          const gchar *greeting;

          g_variant_get (parameters, "(&s)", &greeting);

          if (g_strcmp0 (greeting, "Return Unregistered") == 0)
          
              g_dbus_method_invocation_return_error (invocation,
              G_IO_ERROR,
              G_IO_ERROR_FAILED_HANDLED,
              "As requested, here's a GError not registered 
              (G_IO_ERROR_FAILED_HANDLED)");
          
          else if (g_strcmp0 (greeting, "Return Registered") == 0)
          
              g_dbus_method_invocation_return_error (invocation,
              G_DBUS_ERROR,
              G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
              "As requested, here's a GError that is registered 
              (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
          
          else if (g_strcmp0 (greeting, "Return Raw") == 0)
          
              g_dbus_method_invocation_return_dbus_error (invocation,
              "org.gtk.GDBus.SomeErrorName",
              "As requested, here's a raw D-Bus error");
          
          else
          
              gchar *response;
             response = g_strdup_printf ("You greeted me with 
             '%s'.Thanks!", greeting);
              g_dbus_method_invocation_return_value (invocation,
                        g_variant_new ("(s)", response));
                        g_free (response);
          
      
      else
      
          g_dbus_method_invocation_return_error (invocation,
                                   G_IO_ERROR,
                                   G_IO_ERROR_INVALID_ARGUMENT,
                                   "[server 0] Invalid method: '%s'",
                                          method_name);
      
 // handle_method_call

/*  Handle a request to set a property. */
static gboolean handle_set_property (GDBusConnection  *connection,
                     const gchar      *sender,
                     const gchar      *object_path,
                     const gchar      *interface_name,
                     const gchar      *property_name,
                     GVariant         *value,
                     GError          **error,
                     gpointer          user_data)

    printf("handle_set_property\n");
/*  Print an optional log message   */
#ifdef VERBOSE
  gchar *valstr = g_variant_print (value, TRUE);
  fprintf (stderr, "[server 0] "
           "handle_set_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",
           \"%s\",(error),%p)\n",
           connection, sender, object_path, 
           interface_name, property_name,
           valstr, user_data);
  g_free (valstr);
#endif

  g_set_error (error,
               G_IO_ERROR,
               G_IO_ERROR_FAILED,
               "[server 0] No such property: '%s'",
               property_name);
  return 0;
 // handle_set_property


/** Bus Callbacks   **/

/*  When the bus gets acquired...   */
static void on_bus_acquired (GDBusConnection *connection,
                 const gchar     *name,
                 gpointer        user_data)

    printf("on_bus_acquired\n");
  static GDBusInterfaceVTable interface_vtable =
    
      handle_method_call,
      handle_get_property,
      handle_set_property
    ;

  guint registration_id;
//  GError *error = NULL;

  // An optional notification
#ifdef VERBOSE
  fprintf (stderr, "[server 0] on_bus_acquired (%p, \"%s\", %p)\n",
           connection, name, user_data);
#endif

  registration_id = g_dbus_connection_register_object (connection,
                             object_path,
                             introspection_data->interfaces[0],
                             &interface_vtable,
                             NULL,    // Optional user data
                             NULL,    // Func. for freeing user data
                             NULL); // GError

  // Check to see whether or not the call succeeded.
  printf("g_assert registration_id = %d\n", registration_id);
  g_assert (registration_id > 0);

 // on_bus_acquired

static void on_name_acquired (GDBusConnection *connection,
                  const gchar     *name,
                  gpointer         user_data)


// An optional notification
#ifdef VERBOSE
  fprintf (stderr, "[server 0] on_name_acquired (%p, \"%s\", %p)\n",
           connection, name, user_data);
#endif
 // on_name_acquired

static void on_name_lost (GDBusConnection *connection,
              const gchar     *name,
              gpointer         user_data)


// An optional notification
#ifdef VERBOSE
  fprintf (stderr, "[server 0] on_name_lost (%p, \"%s\", %p)\n",
           connection, name, user_data);
#endif
  // Things seem to have gone badly wrong, so give up
  exit (1);
 // on_name_lost



/** Main    **/

void *dbusLoop(void *dbusParam)

  guint owner_id;
  GMainLoop *loop;
  printf("Reached dbusLoop\n");

  // Build an internal representation of the interface
  printf("Register the object\n");
  introspection_data = g_dbus_node_info_new_for_xml     
  (introspection_xml, NULL);
  g_assert (introspection_data != NULL);

  // Request the name on the bus
  owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
                             service,
                             G_BUS_NAME_OWNER_FLAGS_NONE,
                             on_bus_acquired,
                             on_name_acquired,
                             on_name_lost,
                             NULL,
                             NULL);

  // Start the main loop
  printf("Start the loop\n");
  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (loop);

  // Tell the bus that we're done with the name
  printf("Release the owner_id\n");
  g_bus_unown_name (owner_id);

  // Clean up after ourselves

  g_dbus_node_info_unref (introspection_data);

  //Exit and join main thread
    pthread_exit(NULL);
 // main

我的命令行语句是:

dbus-send --session --print-reply --type=method_call --dest=org.test.DBusClient /org/test/DBusObject org.test.DBusClientInterface.test_method_start string:"Hello"

响应是:

方法返回 sender=:1.364 -> dest=:1.376 reply_serial=2 string "你用‘你好’打招呼。谢谢!”

我现在应该怎么做才能让“test_method_start”运行?

感谢您的帮助。

【问题讨论】:

【参考方案1】:

你不应该在你没有启动的线程上调用pthread_exittest_method_start 被其他人创建的线程调用。

当您从未在任何地方呼叫它或获取其地址时,您如何期望test_method_start 被呼叫? DBUS 没有魔力;如果你想调用它,你必须从handle_method_call 调用它。您似乎有检查方法名称是否为“test_method_start”的代码,因此您可以在 if 中调用它。

【讨论】:

您好,感谢您的回复。我没有分享整个代码,因为它是机密的。为 DBUS 创建了一个线程,当 test_method_start 函数运行时,它也应该创建一个线程。我也是线程新手。正如您所建议的,我确实尝试从“if”语句中的“handle_method_call”函数调用该函数,但我没有得到任何输出。因此,我认为还有其他一些机制用于运行该功能。我看过的所有示例都没有显示对请求运行的函数的任何调用。我会再试试你的建议。谢谢!

以上是关于在发出 dbus-send 命令后,如何使用 C 调用方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 dbus-send 调用 org.bluez.Adapter1.StartDiscovery?

使用 dbus-send 设置/获取属性

如何隐藏来自 dbus-send(打印回复)的响应?

从 shell dbus-send 在 C 中调用 dbus

使用 dbus-send 关闭 Linux

dbus-send