必要條件
本教學課程以 FIDL 伺服器教學課程為基礎。如需完整的 FIDL 教學課程,請參閱總覽。
總覽
本教學課程將實作 FIDL 通訊協定的用戶端,並以上一個教學課程中建立的伺服器執行該用戶端。本教學課程中的用戶端處於同步狀態。另有非同步用戶端的替代教學課程。
如果您要自行編寫程式碼,請刪除下列目錄:
rm -r examples/fidl/hlcpp/client_sync/*
建立元件
在 examples/fidl/hlcpp/client_sync
建立新的元件專案:
將
main()
函式新增至examples/fidl/hlcpp/client_sync/main.cc
: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" }, ], }
建立元件後,請確認可將元件加入建構設定:
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()
函式的程式碼,以連線至伺服器,並向伺服器提出要求。
初始化 Proxy 類別
然後程式碼會為 Echo
通訊協定建立 Proxy 類別,並連線至伺服器。在 FIDL 中,Proxy 會指定 FIDL 繫結產生的程式碼,讓使用者可以向伺服器發出遠端程序呼叫。在 HLCPP 中,Proxy 會採用一個類別的格式,其中包含對應至各個 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
能力從伺服器轉送至用戶端。
設定建構以納入提供的套件,當中包含 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