| # Implement a FIDL client |
| |
| ## Prerequisites |
| |
| This tutorial builds on the [FIDL server][server-tut] tutorial. For the |
| full set of FIDL tutorials, refer to the [overview][overview]. |
| |
| ## Overview |
| |
| This tutorial implements a client for a FIDL protocol and runs it |
| against the server created in the [previous tutorial][server-tut]. The client in this |
| tutorial is synchronous. There is an [alternate tutorial][async-client] for |
| asynchronous clients. |
| |
| If you want to write the code yourself, delete the following directories: |
| |
| ``` |
| rm -r examples/fidl/hlcpp/client_sync/* |
| ``` |
| |
| ## Create a stub component |
| |
| Note: If necessary, refer back to the [previous tutorial][server-tut-component]. |
| |
| 1. Set up a hello world component in `examples/fidl/hlcpp/client`. |
| You can name the component `echo-client`, and give the package a name of |
| `echo-hlcpp-client-sync`. |
| |
| 1. Once you have created your component, ensure that the following works: |
| |
| ``` |
| fx set core.x64 --with //examples/fidl/rust/client |
| ``` |
| |
| 1. Build the Fuchsia image: |
| |
| ``` |
| fx build |
| ``` |
| |
| 1. In a separate terminal, run: |
| |
| ``` |
| fx serve |
| ``` |
| |
| 1. In a separate terminal, run: |
| |
| ``` |
| fx shell run fuchsia-pkg://fuchsia.com/echo-hlcpp-client-sync#meta/echo-client.cmx |
| ``` |
| |
| ## Edit GN dependencies |
| |
| 1. Add the following dependencies: |
| |
| ```gn |
| {%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/client_sync/BUILD.gn" region_tag="deps" %} |
| ``` |
| |
| 1. Then, include them in `main.cc`: |
| |
| ```cpp |
| {%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/client/main.cc" region_tag="includes" %} |
| ``` |
| |
| The reason for including these dependencies is explained in the |
| [server tutorial][server-tut-deps]. |
| |
| ## Edit component manifest |
| |
| 1. Include the `Echo` protocol in the client component's sandbox by |
| editing the component manifest in `client.cmx`. |
| |
| ```cmx |
| {%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/client/client.cmx" %} |
| ``` |
| |
| ## Connect to the server |
| |
| This section adds code the `main()` function that connects to the server and makes |
| requests to it. |
| |
| ### Initialize a proxy class |
| |
| The code then creates a proxy class for the `Echo` protocol, and connects it |
| to the server. In the context of FIDL, proxy designates the code |
| generated by the FIDL bindings that enables users to make |
| remote procedure calls to the server. In HLCPP, the proxy takes the form |
| of a class with methods corresponding to each FIDL protocol method. |
| |
| ```cpp |
| {%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/client_sync/main.cc" region_tag="main" highlight="2,3,4" %} |
| ``` |
| |
| * [`fuchsia::examples::EchoSyncPtr`][proxy] is an alias for |
| `fidl::SynchronousInterfaceRequest<fuchsia::examples::Echo>` generated by the bindings. |
| This class will proxy requests for the `Echo` protocol over the channel that |
| it is bound to. |
| * The code calls `EchoSyncPtr::NewRequest()`, which will create a channel, bind the class to |
| one end, and return the other end |
| * The returned end is passed to `sys::ServiceDirectory::Connect()`. |
| * Analogous to the call to `context->out()->AddPublicService()` on the server |
| side, `Connect` has an implicit second parameter here, which is the protocol |
| name (`"fuchsia.examples.Echo"`). This is where the input to the handler |
| defined in the [previous tutorial][server-tut-handler] comes from: the |
| client passes it in to `Connect`, which then passes it to the handler. |
| |
| An important point to note here is that this code assumes that `/svc` already |
| contains an instance of the `Echo` protocol. This is not the case by default |
| because of the sandboxing provided by the component framework. |
| |
| ### Send requests to the server |
| |
| The code makes two requests to the server: |
| |
| * An `EchoString` request |
| * A `SendString` request |
| |
| ```cpp |
| {%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/hlcpp/client_sync/main.cc" region_tag="main" highlight="6,7,8" %} |
| ``` |
| |
| For `EchoString` the code passes in a pointer for each response parameter (in |
| this case, the `EchoString` method only has one response parameter), which is |
| written with the response from the server, whereas this does not apply to |
| `SendString` since it is a [fire and forget method][one-way]. The call to |
| `EchoString` will block until it receives a message from the server. Both methods |
| will return a `zx_status_t` indicating the result of the method call. |
| |
| Though the [server implementation][server-tut-impl] sends an `OnString` event |
| in response to the `SendString` request, the sync bindings do not provide a |
| way to handle this event. |
| |
| ## Run the client |
| |
| If you try running the client directly, you'll notice that the error handler |
| gets called because the client does not automatically get the `Echo` protocol |
| provided in its sandbox (in `/svc`). In order to get this to work, a launcher |
| tool is provided that launches the server, creates a new |
| [`Environment`][environment] for the client that provides the server's protocol, |
| then launches the client in it. |
| |
| 1. Configure your GN build: |
| |
| ``` |
| fx set core.x64 --with //examples/fidl/hlcpp/server --with |
| //examples/fidl/hlcpp/client_sync --with //examples/fidl/test:echo-launcher |
| ``` |
| |
| 2. Build the Fuchsia image: |
| |
| ``` |
| fx build |
| ``` |
| |
| 3. Run the launcher by passing it the client URL, the server URL, and |
| the protocol that the server provides to the client: |
| |
| ``` |
| fx shell run fuchsia-pkg://fuchsia.com/echo-launcher#meta/launcher.cmx fuchsia-pkg://fuchsia.com/echo-hlcpp-client-sync#meta/echo-client.cmx fuchsia-pkg://fuchsia.com/echo-hlcpp-server#meta/echo-server.cmx fuchsia.examples.Echo |
| ``` |
| |
| You should see the client print output in the QEMU console (or using `fx log`). |
| |
| ``` |
| [117942.207] 757245:757247> Running echo server |
| [117942.223] 757349:757352> Got response: hello |
| ``` |
| |
| <!-- xrefs --> |
| [client-tut-main]: /docs/development/languages/fidl/tutorials/hlcpp/client.md#proxy |
| [server-tut]: /docs/development/languages/fidl/tutorials/hlcpp/basics/server.md |
| [server-tut-component]: /docs/development/languages/fidl/tutorials/hlcpp/basics/server.md#component |
| [server-tut-impl]: /docs/development/languages/fidl/tutorials/hlcpp/basics/server.md#impl |
| [server-tut-deps]: /docs/development/languages/fidl/tutorials/hlcpp/basics/server.md#dependencies |
| [server-tut-handler]: /docs/development/languages/fidl/tutorials/hlcpp/basics/server.md#handler |
| [async-client]: /docs/development/languages/fidl/tutorials/hlcpp/basics/client.md |
| [proxy]: /docs/reference/fidl/bindings/hlcpp-bindings.md#protocols-client |
| [overview]: /docs/development/languages/fidl/tutorials/overview.md |
| [environment]: /docs/concepts/components/v2/environments.md |