前提条件
本教程基于 FIDL 服务器教程构建。如需查看完整的 FIDL 教程,请参阅概览。
概览
本教程实现了 FIDL 协议的客户端,并针对在前一个教程中创建的服务器运行该客户端。本教程中的客户端是同步客户端。我们提供了针对异步客户端的备用教程。
如果您要自行编写代码,请删除以下目录:
rm -r examples/fidl/hlcpp/client_sync/*
创建组件
在 examples/fidl/hlcpp/client_sync
中创建一个新的组件项目:
向
examples/fidl/hlcpp/client_sync/main.cc
添加main()
函数:int main(int argc, const char** argv) { printf("Hello, world!\n"); return 0; }
在
examples/fidl/hlcpp/client_sync/BUILD.gn
中声明客户端的目标:import("//build/components.gni") # Declare an executable for the client. executable("bin") { output_name = "fidl_echo_hlcpp_client_sync" sources = [ "main.cc" ] } fuchsia_component("echo-client") { component_name = "echo_client" manifest = "meta/client.cml" deps = [ ":bin" ] }
在
examples/fidl/hlcpp/client_sync/meta/client.cml
中添加组件清单:{ include: [ "syslog/client.shard.cml" ], // Information about the program to run. program: { // Use the built-in ELF runner. runner: "elf", // The binary to run for this component. binary: "bin/fidl_echo_hlcpp_client_sync", }, // Capabilities used by this component. use: [ { protocol: "fuchsia.examples.Echo" }, ], }
创建组件后,请确保可以将其添加到 build 配置中:
fx set core.x64 --with //examples/fidl/hlcpp/client_sync:echo-client
构建 Fuchsia 映像:
fx build
修改 GN 依赖项
添加以下依赖项:
deps = [ "//examples/fidl/fuchsia.examples:fuchsia.examples_hlcpp", "//sdk/lib/sys/cpp", ]
然后,将它们包含在
main.cc
中:#include <fuchsia/examples/cpp/fidl.h> #include <lib/sys/cpp/component_context.h>
服务器教程中介绍了添加这些依赖项的原因。
连接到服务器
本部分将代码添加到 main()
函数,该函数可连接到服务器并向其发出请求。
初始化代理类
然后,该代码为 Echo
协议创建代理类,并将其连接到服务器。在 FIDL 环境中,代理会指定由 FIDL 绑定生成的代码,使用户能够对服务器进行远程过程调用。在 HLCPP 中,代理采用类的形式,其中包含与每个 FIDL 协议方法相对应的方法。
int main(int argc, const char** argv) {
fuchsia::examples::EchoSyncPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
ZX_ASSERT(echo_proxy->SendString("hi") == ZX_OK);
std::string response;
ZX_ASSERT(echo_proxy->EchoString("hello", &response) == ZX_OK);
printf("Got response: %s\n", response.c_str());
// TODO(fcz): this currently does not pass on CQ
// return response == "hello" ? 0 : 1;
return 0;
}
fuchsia::examples::EchoSyncPtr
是绑定生成的fidl::SynchronousInterfaceRequest<fuchsia::examples::Echo>
的别名。此类将通过其绑定到的通道代理对Echo
协议的请求。- 代码调用
EchoSyncPtr::NewRequest()
,这将创建一个通道,将该类绑定到一端,并返回另一端 - 返回的末尾会传递给
sys::ServiceDirectory::Connect()
。- 与在服务器端调用
context->out()->AddPublicService()
类似,Connect
在这里有一个隐式的第二个参数,即协议名称 ("fuchsia.examples.Echo"
)。这是上一个教程中定义的处理程序的输入来源:客户端将其传入Connect
,后者随后将其传递给处理程序。
- 与在服务器端调用
此处需要注意的要点是,此代码假定 /svc
已包含 Echo
协议的实例。由于组件框架提供了沙盒,因此默认情况下情况并非如此。
向服务器发送请求
该代码会向服务器发出两个请求:
EchoString
请求SendString
请求
int main(int argc, const char** argv) {
fuchsia::examples::EchoSyncPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
ZX_ASSERT(echo_proxy->SendString("hi") == ZX_OK);
std::string response;
ZX_ASSERT(echo_proxy->EchoString("hello", &response) == ZX_OK);
printf("Got response: %s\n", response.c_str());
// TODO(fcz): this currently does not pass on CQ
// return response == "hello" ? 0 : 1;
return 0;
}
对于 EchoString
,代码会为每个响应参数传入一个指针(在本例中,EchoString
方法只有一个响应参数),该指针随服务器的响应一起写入,但这不适用于 SendString
,因为它是一种“即发即弃”方法。对 EchoString
的调用将一直保持阻止状态,直到它收到来自服务器的消息。这两种方法都将返回一个 zx_status_t
,以指示方法调用的结果。
虽然服务器实现会发送 OnString
事件来响应 SendString
请求,但同步绑定未提供处理此事件的方法。
运行客户端
为了让客户端和服务器使用 Echo
协议进行通信,组件框架必须将 fuchsia.examples.Echo
功能从服务器路由到客户端。
配置 build 以添加所提供的包含 echo 领域、服务器和客户端的软件包:
fx set core.x64 --with //examples/fidl/hlcpp:echo-hlcpp-client-sync
构建 Fuchsia 映像:
fx build
运行
echo_realm
组件。这会创建客户端和服务器组件实例并路由功能:ffx component run /core/ffx-laboratory:echo_realm fuchsia-pkg://fuchsia.com/echo-hlcpp-client-sync#meta/echo_realm.cm
启动
echo_client
实例:ffx component start /core/ffx-laboratory:echo_realm/echo_client
服务器组件在客户端尝试连接到 Echo
协议时启动。您应该会在设备日志 (ffx log
) 中看到类似于以下内容的输出:
[echo_server][][I] Running echo server
[echo_client][][I] Got response: hello
终止领域组件以停止执行并清理组件实例:
ffx component destroy /core/ffx-laboratory:echo_realm