如何使D-Bus服务器端调用为异步?

时间:2017-08-06 07:02:04

标签: linux qt dbus gdbus

对于我的项目,我使用DBUS作为IPC在QT应用程序(客户端)和我的服务守护程序(服务器端 - GIO / GDBUS)之间进行交互。在客户端,使用QDBusPendingCallWatcher异步调用方法。

但是在服务器端,如何将方法调用作为异步? 。根据我的理解," g_dbus_method_invocation_return_value"将使用输出参数返回响应,使方法调用为同步。

我能想到的一种方法是使用g_dbus_method_invocation_return_value返回中间响应,然后在收到最终响应后发出最终响应作为信号。

示例代码: -

//Method invocation      

static void handle_method_call(GDBusConnection *conn,
                               const gchar *sender,
                               const gchar *object_path,
                               const gchar *interface_name,
                               const gchar *method_name,
                               GVariant *parameters,
                               GDBusMethodInvocation *invocation,
                               gpointer user_data)

{

    if (!g_strcmp0(method_name, "Scan")) {
        guint8 radiotype = 0;
        guint8temp_resp = 0 ;
        g_variant_get(parameters, "(y)", radiotype);
        // Async Function Call and takes very 
        // long time to return final response as needs to scan whole radio band 
        temp_resp = RadioScan(radiotype); 

        g_dbus_method_invocation_return_value(invocation, g_variant_new("(y", temp_resp)); // return intermediate response to client  and when final response is received then  emit the signal
        g_free(response);
    }
}
// Final scan response callback function
static gboolean on_scanfinalresponse_cb (gpointer user_data)
{

    GDBusConnection *connection = G_DBUS_CONNECTION (user_data);

    GVariantBuilder *builder;

    GVariantBuilder *invalidated_builder;

    GError *error;
    g_dbus_connection_emit_signal (connection,
                                   NULL,
                                   "/org/example/test",
                                   "org.example.test",
                                   "ScanFinalResponse",
                                   g_variant_new ("(s)",
                                                  builder),
                                   &error);
    g_assert_no_error (error);
    return TRUE;
}

请告诉我这是正确的方法还是有更好的方法来实现上述情况的异步调用?

1 个答案:

答案 0 :(得分:2)

  

但是在服务器端,如何将方法调用作为异步?

这里有两个概念你可能指的是“async”,而D-Bus(或GDBus)并不限制你。

  1. API设计:如果您可以修改实际公开的API,您当然可以创建一个立即返回的方法,然后通过属性更改或信号“返回值”。对于像Wi-Fi扫描调用这样的特定情况,这可能是一个好主意。

  2. 方法实现:您的API可能有一个在返回之前需要很长时间的方法,并且它可能是“异步”实现的,因为您的服务在方法未返回时不会阻塞 - 其他方法可以调用,在此期间可能发生信号和属性更改。 g_dbus_method_invocation_return_*函数可用于实现此功能。创建长时间运行的D-Bus方法不是问题,只要它们被记录为:客户端可以异步处理调用,甚至可以根据需要增加默认方法调用超时。

  3. 在您发布的示例代码的上下文中,您需要做的第一件事是使RadioScan()调用异步,或者在另一个线程中执行调用:这可以确保您的服务在调用期间保持响应。

    在您的RadioScan异步后,很容易实现任何一种解决方案。如果RadioScan()方法具有明确定义的返回值(并且您不希望先前返回中间结果),我会选择一个需要更长时间的正常方法调用:

    static void handle_method_call(GDBusConnection *conn, ...)
    {
        if (!g_strcmp0(method_name, "Scan")) {
            // start the async scan (maybe using another thread): this should 
            // return immediately and call the callback when scan is done
            start_radio_scan(..., radio_scan_finished_cb); 
            // do not return the invocation here, just store a pointer to it          
        }
    }
    
    static void radio_scan_finished_cb (...)
    {
        // return the D-Bbus method call with the invocation that was stored earlier
        g_dbus_method_invocation_return_value(invocation, ...)
    }
    

    如果您的扫描结果实际上是随着时间的推移而到达的(例如,1秒后的第一个结果,3秒后的更多结果),将结果作为信号实际返回时可能有意义,然后将方法调用返回为扫描终于完成的标志。

    单个“ScanFinalResponse”信号肯定是可能的,但我认为通过一个花费更长时间的方法调用来做这件事并没有任何好处。