前提条件
本教程以入门教程为基础。
概览
本教程的完整示例代码位于 //examples/fidl/cpp/server_async_completer。
在初始服务器教程的 Echo 实现中,服务器代码使用 completer 响应 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 请求,我们可能就会有同样多的并发异步延迟任务在运行。
在服务器上以异步方式响应,并使用线网域对象
如果服务器使用序列化网域对象,您可以使用相同的 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 以包含提供的软件包,该软件包包含回显 realm、服务器和客户端:
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