Prerequisites
This tutorial builds on the HLCPP getting started tutorials.
Overview
This tutorial updates the Echo client from the getting started tutorials to make multiple connections to the server, and update the Echo server to handle multiple client connections. For running multiple instances of a server (or multiple FIDL protocols), see the tutorial on services.
The full example code for this tutorial is located at
//examples/fidl/hlcpp/multiple_clients
.
Implement the server
In the previous implementation, the main()
function initialized
a single fidl::Binding
, and bound any incoming requests to it:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
EchoImpl impl;
fidl::Binding<fuchsia::examples::Echo> binding(&impl);
impl.event_sender_ = &binding.events();
fidl::InterfaceRequestHandler<fuchsia::examples::Echo> handler =
[&](fidl::InterfaceRequest<fuchsia::examples::Echo> request) {
binding.Bind(std::move(request));
};
auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
context->outgoing()->AddPublicService(std::move(handler));
printf("Running echo server\n");
return loop.Run();
}
This means that if a second client tries to connect to the server at the same
time, the second call to binding.Bind
will overwrite the channel from the
first client. To support multiple clients, keep track of multiple
fidl::Binding
s (one for each client) using a fidl::BindingSet
:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
EchoImpl impl;
fidl::BindingSet<fuchsia::examples::Echo> bindings;
auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
context->outgoing()->AddPublicService(bindings.GetHandler(&impl));
printf("Running echo server\n");
return loop.Run();
}
A binding set also simplifies the code since it no longer
needs to create a custom handler. The binding set has a GetHandler
method,
which returns a handler that creates a new Binding
and stores it in a vector.
To use fidl::BindingSet
, include lib/fidl/cpp/binding_set.h
.
Implement the client
In order to manage multiple clients connected to a protocol, the FIDL HLCPP
runtime library provides an anolog to fidl::BindingSet
: the
fidl::InterfacePtrSet
. Use the class to write code that makes multiple
connections to the same protocol:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto context = sys::ComponentContext::Create();
fidl::InterfacePtrSet<fuchsia::examples::Echo> echoers;
for (int i = 0; i < kNumClients; i++) {
fuchsia::examples::EchoPtr proxy;
context->svc()->Connect(proxy.NewRequest());
proxy.set_error_handler([&loop](zx_status_t status) {
std::cout << "Error reading incoming message: " << status << std::endl;
loop.Quit();
});
echoers.AddInterfacePtr(std::move(proxy));
}
size_t responses = 0;
for (auto& echoer : echoers.ptrs()) {
(*echoer)->EchoString("Hello echoer " + std::to_string(responses++), [&](std::string response) {
std::cout << "Got response " << response << std::endl;
if (responses == echoers.size()) {
loop.Quit();
}
});
}
loop.Run();
return responses == kNumClients ? 0 : 1;
}
The code for setting up a proxy and making requests is the same as in the
client tutorial except it uses
an interface pointer set to simplify the process of broadcasting a message
to a set of clients. An added benefit of using fidl::InterfacePtrSet
and
fidl::BindingSet
is that any binding or interface pointer that experiences an
error on its channel is automatically removed from the set.
To use fidl::InterfacePtrSet
, include lib/fidl/cpp/interface_ptr_set.h
.
Run the example
In order for the client and server to communicate using the Echo
protocol,
component framework must route the fuchsia.examples.Echo
capability from the
server to the client. For this tutorial, a
realm
component is
provided to declare the appropriate capabilities and routes.
Configure your build to include the provided package that includes the echo realm, server, and client:
fx set core.x64 --with //examples/fidl/hlcpp:echo-hlcpp-multi-client
Build the Fuchsia image:
fx build
Run the
echo_realm
component. This creates the client and server component instances and routes the capabilities:ffx component run /core/ffx-laboratory:echo_realm fuchsia-pkg://fuchsia.com/echo-hlcpp-multi-client#meta/echo_realm.cm
Start the
echo_client
instance:ffx component start /core/ffx-laboratory:echo_realm/echo_client
The server component starts when the client attempts to connect to the Echo
protocol. You should see output similar to the following in the device logs
(ffx log
):
[echo_server][][I] Running echo server
[echo_client][][I] Got response Hello echoer 0
Terminate the realm component to stop execution and clean up the component instances:
ffx component destroy /core/ffx-laboratory:echo_realm