前提条件
本教程基于入门教程。
概览
本教程的完整示例代码位于 //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 消息,同时将回复安排在 1 秒后发送。这意味着,如果客户端快速连续发送多个 EchoString
请求,我们可能会有同样多的并发异步延迟任务正在处理中。
在使用 Wire 网域对象的服务器中异步响应
当服务器使用线程域对象时,您可以使用相同的 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
capability 从服务器路由到客户端。在本教程中,我们提供了一个 realm 组件来声明适当的 capability 和路由。
配置 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
之间大约需要一秒钟的时间,因为服务器被编程为异步延迟一秒钟的响应。
终止 Realm 组件以停止执行并清理组件实例:
ffx component destroy /core/ffx-laboratory:echo_realm