3

对于我的项目,我使用 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;
}

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

4

1 回答 1

3

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

您可能在这里使用“异步”来指代两个概念,而 D-Bus(或 GDBus)不会限制您使用其中任何一个。

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

  2. 方法实现:您的 API 可能有一个方法在返回之前需要很长时间,并且它可能是“异步”实现的,因为您的服务在方法没有返回时不会阻塞——可以调用其他方法并发出信号和在此期间可能会发生财产变化。g_dbus_method_invocation_return_*可以使用函数来实现这一点。创建长时间运行的 D-Bus 方法不是问题,只要它们是这样记录的:客户端可以异步处理调用,甚至可以在需要时增加默认方法调用超时。

在您发布的示例代码的上下文中,您需要做的第一件事是使 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”信号当然是可能的,但我认为这样做比只需要更长时间的方法调用有任何优势。

于 2017-08-06T10:59:53.907 回答