必要條件
本教學課程是以 FIDL 伺服器教學課程為基礎。對於 完整的 FIDL 教學課程,請參閱總覽。
總覽
本教學課程將實作 FIDL 通訊協定的用戶端,並執行 您在上一個教學課程中建立的伺服器。這個架構中的用戶端 以及非同步教學課程我們也提供替代的教學課程 同步用戶端。
若您想要自行編寫程式碼,請刪除下列目錄:
rm -r examples/fidl/hlcpp/client/*
建立元件
在 examples/fidl/hlcpp/client
建立新的元件專案:
將
main()
函式新增至examples/fidl/hlcpp/client/main.cc
:int main(int argc, const char** argv) { printf("Hello, world!\n"); return 0; }
在
examples/fidl/hlcpp/client/BUILD.gn
中宣告用戶端的目標:import("//build/components.gni") # Declare an executable for the client. executable("bin") { output_name = "fidl_echo_hlcpp_client" sources = [ "main.cc" ] } fuchsia_component("echo-client") { component_name = "echo_client" manifest = "meta/client.cml" deps = [ ":bin" ] }
在
examples/fidl/hlcpp/client/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", }, // Capabilities used by this component. use: [ { protocol: "fuchsia.examples.Echo" }, ], }
建立元件後,請確定能將其新增至 建構設定:
fx set core.x64 --with //examples/fidl/hlcpp/client:echo-client
建構 Fuchsia 映像檔:
fx build
編輯 GN 依附元件
新增下列依附元件:
deps = [ "//examples/fidl/fuchsia.examples:fuchsia.examples_hlcpp", "//sdk/lib/sys/cpp", "//zircon/system/ulib/async-loop:async-loop-cpp", "//zircon/system/ulib/async-loop:async-loop-default", ]
然後在
main.cc
中加入:#include <fuchsia/examples/cpp/fidl.h> #include <lib/async-loop/cpp/loop.h> #include <lib/async-loop/default.h> #include <lib/sys/cpp/component_context.h>
如要瞭解加入這些依附元件的原因,請參閱 伺服器教學課程。
連線至伺服器
本節中的步驟說明如何在 main()
函式中新增程式碼
這個網路可讓用戶端連上伺服器,並向伺服器發出要求。
初始化事件迴圈
和在伺服器一樣,程式碼會先設定非同步迴圈,讓用戶端可以 監聽來自伺服器的傳入回應,而不會遭到封鎖。
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Error reading incoming message: %d\n", status);
loop.Quit();
});
int num_responses = 0;
echo_proxy->SendString("hi");
echo_proxy->EchoString("hello", [&](std::string response) {
printf("Got response %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
});
echo_proxy.events().OnString = [&](std::string response) {
printf("Got event %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
};
printf("Async loop starting\n");
loop.Run();
printf("Async loop finished\n");
return num_responses == 2 ? 0 : 1;
}
初始化 Proxy 類別
在 FIDL 的環境中,Proxy 會指定程式碼 您可以利用 FIDL 繫結產生程式碼,讓使用者可以 對伺服器發出的遠端程序呼叫。在 HLCPP 中,Proxy 會採用以下形式: 以及每個 FIDL 通訊協定方法對應的方法。
接著,程式碼會建立 Echo
通訊協定的 Proxy 類別並連線
傳送到伺服器
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Error reading incoming message: %d\n", status);
loop.Quit();
});
int num_responses = 0;
echo_proxy->SendString("hi");
echo_proxy->EchoString("hello", [&](std::string response) {
printf("Got response %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
});
echo_proxy.events().OnString = [&](std::string response) {
printf("Got event %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
};
printf("Async loop starting\n");
loop.Run();
printf("Async loop finished\n");
return num_responses == 2 ? 0 : 1;
}
fuchsia::examples::EchoPtr
是下列機構的別名:fidl::InterfaceRequest<fuchsia::examples::Echo>
是繫結產生的值。- 類似於伺服器中使用的
fidl::Binding<fuchsia::examples::Echo>
。fidl::InterfaceRequest<fuchsia::examples::Echo>
已由 FIDL 參數化 並透過 Proxy 處理要求 以及傳入的回應和事件 - 程式碼會呼叫
EchoPtr::NewRequest()
,藉此建立管道。 會將類別繫結至管道的結尾,並傳回 頻道。 - 管道傳回的結尾會傳遞至
sys::ServiceDirectory::Connect()
。- 與伺服器上對
context->out()->AddPublicService()
的呼叫類似 那邊,Connect
具有隱含的第二個參數,也就是通訊協定 名稱 ("fuchsia.examples.Echo"
)。這就是處理常式的輸入內容 上一個教學課程中定義的值來自: 用戶端會將資料傳入Connect
,再傳遞至處理常式。
- 與伺服器上對
這裡的重點是,這段程式碼假設 /svc
已
包含 Echo
通訊協定的執行個體。根據預設
因為系統必須採用元件架構提供的沙箱機制
設定錯誤處理常式
最後,程式碼會設定 Proxy 的錯誤處理常式:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Error reading incoming message: %d\n", status);
loop.Quit();
});
int num_responses = 0;
echo_proxy->SendString("hi");
echo_proxy->EchoString("hello", [&](std::string response) {
printf("Got response %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
});
echo_proxy.events().OnString = [&](std::string response) {
printf("Got event %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
};
printf("Async loop starting\n");
loop.Run();
printf("Async loop finished\n");
return num_responses == 2 ? 0 : 1;
}
將要求傳送至伺服器
程式碼會向伺服器發出兩項要求:
EchoString
要求SendString
要求
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Error reading incoming message: %d\n", status);
loop.Quit();
});
int num_responses = 0;
echo_proxy->SendString("hi");
echo_proxy->EchoString("hello", [&](std::string response) {
printf("Got response %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
});
echo_proxy.events().OnString = [&](std::string response) {
printf("Got event %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
};
printf("Async loop starting\n");
loop.Run();
printf("Async loop finished\n");
return num_responses == 2 ? 0 : 1;
}
如果是 EchoString
,程式碼會傳入回呼來處理回應。
SendString
不需要這類回呼,因為此方法
有任何回應。
設定事件處理常式
然後,程式碼會為任何傳入的 OnString
事件設定處理常式:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Error reading incoming message: %d\n", status);
loop.Quit();
});
int num_responses = 0;
echo_proxy->SendString("hi");
echo_proxy->EchoString("hello", [&](std::string response) {
printf("Got response %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
});
echo_proxy.events().OnString = [&](std::string response) {
printf("Got event %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
};
printf("Async loop starting\n");
loop.Run();
printf("Async loop finished\n");
return num_responses == 2 ? 0 : 1;
}
終止事件迴圈
程式碼等待收到對 EchoString
方法的回應,以及
OnString
事件 (在目前實作中會在收到
SendString
要求),再退出迴圈。程式碼傳回成功的結束事件
產生程式碼時,應用程式必須同時收到回應和事件:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
echo_proxy.set_error_handler([&loop](zx_status_t status) {
printf("Error reading incoming message: %d\n", status);
loop.Quit();
});
int num_responses = 0;
echo_proxy->SendString("hi");
echo_proxy->EchoString("hello", [&](std::string response) {
printf("Got response %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
});
echo_proxy.events().OnString = [&](std::string response) {
printf("Got event %s\n", response.c_str());
if (++num_responses == 2) {
loop.Quit();
}
};
printf("Async loop starting\n");
loop.Run();
printf("Async loop finished\n");
return num_responses == 2 ? 0 : 1;
}
執行用戶端
為了讓用戶端和伺服器使用 Echo
通訊協定進行通訊,
元件架構必須從 fuchsia.examples.Echo
伺服器傳送至用戶端在本教學課程中
運作範圍
元件是
來宣告適當的功能和路徑
設定您的版本以包含 echo 領域、伺服器和用戶端:
fx set core.x64 --with //examples/fidl/hlcpp:echo-hlcpp-client
建構 Fuchsia 映像檔:
fx build
執行
echo_realm
元件。這項操作會建立用戶端和伺服器元件 以及轉送功能:ffx component run /core/ffx-laboratory:echo_realm fuchsia-pkg://fuchsia.com/echo-hlcpp-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 event hi
[echo_client][][I] Got response hello
終止領域元件以停止執行並清除元件 執行個體:
ffx component destroy /core/ffx-laboratory:echo_realm