必要條件
本教學課程以 HLCPP 入門教學課程為基礎。
總覽
本教學課程會從入門教學課程更新 Echo 用戶端,以建立多個連至伺服器的連線,並更新 Echo 伺服器以處理多個用戶端連線。如要執行多個伺服器的執行個體 (或多個 FIDL 通訊協定),請參閱服務中的教學課程。
本教學課程的完整程式碼範例位於 //examples/fidl/hlcpp/multiple_clients
。
實作伺服器
在先前的實作中,main()
函式會初始化一個 fidl::Binding
,並對所有傳入要求繫結至該函式:
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();
}
也就是說,如果有第二個用戶端同時嘗試連線至伺服器,則對 binding.Bind
發出的第二個呼叫會覆寫第一個用戶端的管道。如要支援多個用戶端,請使用 fidl::BindingSet
追蹤多個 fidl::Binding
(每個用戶端一個):
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();
}
由於繫結組合不再需要建立自訂處理常式,因此也可以簡化程式碼。繫結集具有 GetHandler
方法,此方法會傳回可建立新的 Binding
的處理常式,並將該處理常式儲存至向量。
如要使用fidl::BindingSet
,請加入 lib/fidl/cpp/binding_set.h
。
實作用戶端
為了管理連接至通訊協定的多個用戶端,FIDL HLCPP 執行階段程式庫會向 fidl::BindingSet
提供異常記錄:fidl::InterfacePtrSet
。使用該類別編寫程式碼,讓多個連至同一個通訊協定的連線:
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;
}
設定 Proxy 及發出要求的程式碼與用戶端教學課程相同,差別在於前者使用介面指標集來簡化向一組用戶端廣播訊息的程序。使用 fidl::InterfacePtrSet
和 fidl::BindingSet
的另一個好處是,所有遇到其管道錯誤的繫結或介面指標都會自動從組合中移除。
如要使用fidl::InterfacePtrSet
,請加入 lib/fidl/cpp/interface_ptr_set.h
。
執行範例
為了讓用戶端和伺服器能使用 Echo
通訊協定進行通訊,元件架構必須將 fuchsia.examples.Echo
能力從伺服器轉送至用戶端。
設定建構以納入提供的套件,當中包含 echo 領域、伺服器和用戶端:
fx set core.x64 --with //examples/fidl/hlcpp:echo-hlcpp-multi-client
建構 Fuchsia 映像檔:
fx build
執行
echo_realm
元件。這會建立用戶端和伺服器元件執行個體,並轉送功能:ffx component run /core/ffx-laboratory:echo_realm fuchsia-pkg://fuchsia.com/echo-hlcpp-multi-client#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 echoer 0
終止領域元件以停止執行並清除元件執行個體:
ffx component destroy /core/ffx-laboratory:echo_realm