前提条件
本教程以入门教程为基础。
概览
本教程的完整示例代码位于 //examples/fidl/cpp/server_async_completer。
在初始服务器教程的 Echo
实现中,服务器代码使用补全器响应 EchoString
请求:
void EchoString(EchoStringRequest& request, EchoStringCompleter::Sync& completer) override {
// Call |Reply| to reply synchronously with the request value.
completer.Reply({{.response = request.value()}});
}
请注意,完整器的类型以 ::Sync
结尾。处理程序返回之前,必须使用同步完成器。强制执行此操作可以进行优化,因为用于回复的簿记元数据可以堆栈分配。
异步响应
在许多情况下,同步响应是不可行的。例如,回复可能需要其他异步调用的结果。如需异步响应,我们必须使用 ToAsync
从同步完成器中获取异步完成器:
EchoStringCompleter::Async async_completer = completer.ToAsync();
生成的 async_completer
公开了与 completer
相同的 API,但可以将其移除,以便稍后使用。
在示例代码中,服务器在延迟任务内进行回复,模拟了服务器必须在发送响应之前执行长时间运行的任务的场景:
void EchoString(EchoStringRequest& request, EchoStringCompleter::Sync& completer) override {
async::PostDelayedTask(
dispatcher_,
[value = request.value(), completer = completer.ToAsync()]() mutable {
completer.Reply({{.response = value}});
},
zx::duration(ZX_SEC(1)));
}
在从当前处理程序方法返回之前,服务器不会开始处理任何新请求。从 EchoString
返回后,服务器将监控端点是否有新的 FIDL 消息,同时将回复安排在未来一秒钟后进行。这意味着,如果客户端快速连续发送多个 EchoString
请求,我们的并发异步延迟任务数可能相同。
在代表线路网域对象的服务器中异步响应
当服务器读出有线网域对象时,您可以使用相同的 ToAsync
操作,但要特别注意对象的生命周期。具体来说,提供给方法处理程序的请求视图不拥有请求消息。如果异步任务需要在 EchoString
方法返回后使用请求参数,我们需要将相关字段复制到有主的类型:
class EchoImpl : public fidl::WireServer<fuchsia_examples::Echo> {
public:
void EchoString(EchoStringRequestView request, EchoStringCompleter::Sync& completer) override {
// Copy the contents of |request->value| (a fidl::StringView) to a string.
std::string value_owned{request->value.get()};
async::PostDelayedTask(
dispatcher_,
[value = value_owned, completer = completer.ToAsync()]() mutable {
completer.Reply(fidl::StringView::FromExternal(value));
},
zx::duration(ZX_SEC(1)));
}
// ...
};
如需详细了解内存所有权,请参阅传输域对象的内存所有权。
运行示例
为了让客户端和服务器使用 Echo
协议进行通信,组件框架必须将 fuchsia.examples.Echo
功能从服务器路由到客户端。
配置 build 以添加所提供的包含 echo 领域、服务器和客户端的软件包:
fx set core.x64 --with //examples/fidl/cpp/server_async_completer:echo-cpp-async
构建 Fuchsia 映像:
fx build
运行
echo_realm
组件。这会创建客户端和服务器组件实例并路由功能:ffx component run /core/ffx-laboratory:echo_realm fuchsia-pkg://fuchsia.com/echo-cpp-async#meta/echo_realm.cm
启动
echo_client
实例:ffx component start /core/ffx-laboratory:echo_realm/echo_client
服务器组件在客户端尝试连接到 Echo
协议时启动。您应该会在设备日志 (ffx log
) 中看到类似如下所示的输出。最左边的列是时间戳:
[21611.962][echo_server][I] Running C++ echo server with natural types
[21611.965][echo_server][I] Incoming connection for fuchsia.examples.Echo
[21612.998][echo_client][I] (Natural types) got response: hello
[21613.999][echo_client][I] (Natural types) got response: hello
[21614.000][echo_client][I] (Natural types) got event: hello
[21615.002][echo_client][I] (Wire types) got response: hello
[21615.003][echo_client][I] (Natural types) got event: hello
[21615.003][echo_server][I] Client disconnected
请注意,Incoming connection for fuchsia.examples.Echo
和 (Natural types) got response: hello
之间大约需要 1 秒,因为服务器的编程为异步将响应延迟 1 秒。
终止领域组件以停止执行并清理组件实例:
ffx component destroy /core/ffx-laboratory:echo_realm