必要條件
本教學課程假設您已熟悉如何編寫及執行 Fuchsia 元件,以及如何實作 FIDL 伺服器。這兩項主題都在 FIDL 伺服器教學課程中說明。如需完整的 FIDL 教學課程,請參閱總覽。
總覽
本教學課程會實作 FIDL 通訊協定的用戶端,並針對上一個教學課程中建立的伺服器執行。本教學課程中的用戶端是非同步的。如要瞭解同步用戶端,請參閱替代教學課程。
如要自行編寫程式碼,請刪除下列目錄:
rm -r examples/fidl/rust/client/*建立元件
在 examples/fidl/rust/client 建立新的元件專案:
在
examples/fidl/rust/client/src/main.rs中新增main()函式:fn main() { println!("Hello, world!"); }在
examples/fidl/rust/client/BUILD.gn中為用戶端宣告目標:import("//build/components.gni") import("//build/rust/rustc_binary.gni") # Declare an executable for the client. rustc_binary("bin") { name = "fidl_echo_rust_client" edition = "2024" sources = [ "src/main.rs" ] } fuchsia_component("echo-client") { component_name = "echo_client" manifest = "meta/client.cml" deps = [ ":bin" ] }在
examples/fidl/rust/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_rust_client", }, // Capabilities used by this component. use: [ { protocol: "fuchsia.examples.Echo" }, ], }建立元件後,請確認您可以將其新增至建構設定:
fx set core.x64 --with //examples/fidl/rust/client:echo-client建構 Fuchsia 映像檔:
fx build
編輯 GN 依附元件
在
rustc_binary中新增下列依附元件:deps = [ "//examples/fidl/fuchsia.examples:fuchsia.examples_rust", "//src/lib/fuchsia", "//src/lib/fuchsia-component", "//third_party/rust_crates:anyhow", "//third_party/rust_crates:futures", ]接著,在
main.rs中匯入這些檔案:use anyhow::{Context as _, Error}; use fidl_fuchsia_examples::{EchoEvent, EchoMarker}; use fuchsia_component::client::connect_to_protocol; use futures::prelude::*;
如要瞭解這些依附元件,請參閱伺服器教學課程。
連線至伺服器
本節的步驟說明如何將程式碼新增至 main() 函式,將用戶端連線至伺服器,並向伺服器發出要求。
連線至伺服器
#[fuchsia::main]
async fn main() -> Result<(), Error> {
// Connect to the Echo protocol, which is assumed to be in the component's environment
let echo = connect_to_protocol::<EchoMarker>().context("Failed to connect to echo service")?;
// Make an EchoString request and wait for the response
let res = echo.echo_string("hello").await?;
println!("response: {:?}", res);
// Make a SendString request
echo.send_string("hi")?;
// Wait for a single OnString event
let EchoEvent::OnString { response } =
echo.take_event_stream().next().await.context("error receiving events")??;
println!("Received OnString event for string {:?}", response);
Ok(())
}
在幕後,這個呼叫會觸發一連串事件,這些事件會從用戶端開始,並追蹤先前教學課程中的伺服器程式碼。
- 初始化用戶端物件和管道。用戶端物件會繫結至管道的一端。
- 向元件架構發出要求,其中包含要連線的服務名稱和管道的另一端。服務名稱是使用
SERVICE_NAMEEchoMarker範本引數隱含取得,與伺服器端判斷服務路徑的方式類似。 - 這個用戶端物件是從
connect_to_protocol傳回。
在背景中,對元件架構的要求會轉送至伺服器:
- 伺服器程序收到這項要求後,會喚醒
async::Executor執行器,並告知ServiceFs工作現在可以繼續執行。 ServiceFs會喚醒,查看程序啟動控制代碼上可用的要求,並在透過呼叫add_service、add_fidl_service等提供的(service_name, service_startup_func)清單中,查閱所要求服務的名稱。如果存在相符的service_name,則會使用提供的管道呼叫service_startup_func,以連線至新服務。IncomingService::Echo會使用向add_fidl_service註冊的EchoFIDL 通訊協定 (型別管道) 呼叫。RequestStream傳入要求管道會儲存在IncomingService::Echo中,並新增至傳入要求串流。for_each_concurrent會將ServiceFs併入IncomingService類型的Stream中。系統會針對串流中的每個項目執行處理常式,比對傳入的要求,並分派至run_echo_server。當ServiceFs串流await時,對run_echo_server的每次呼叫所產生的 Future 會並行執行。- 當要求透過管道傳送時,
Echo服務的管道會變成可讀取狀態,這會喚醒run_echo_server主體中的非同步程式碼。
將要求傳送至伺服器
程式碼會向伺服器發出兩項要求:
EchoString要求SendString要求
#[fuchsia::main]
async fn main() -> Result<(), Error> {
// Connect to the Echo protocol, which is assumed to be in the component's environment
let echo = connect_to_protocol::<EchoMarker>().context("Failed to connect to echo service")?;
// Make an EchoString request and wait for the response
let res = echo.echo_string("hello").await?;
println!("response: {:?}", res);
// Make a SendString request
echo.send_string("hi")?;
// Wait for a single OnString event
let EchoEvent::OnString { response } =
echo.take_event_stream().next().await.context("error receiving events")??;
println!("Received OnString event for string {:?}", response);
Ok(())
}
對 EchoString 的呼叫會傳回 future,該 future 會解析為伺服器傳回的回應。如果傳送要求或接收回應時發生錯誤 (例如解碼訊息時,或收到墓誌銘),傳回的 Future 會解析為錯誤。
另一方面,由於 SendString 是「即發即忘」方法,因此呼叫 SendString 會傳回 Result。如果傳送要求時發生問題,這個方法呼叫會傳回錯誤。
繫結參考資料說明如何產生這些 Proxy 方法,而 Fuchsia rustdoc 則包含產生的 FIDL Crate 的說明文件。
處理傳入事件
接著,程式碼會等待伺服器傳送單一 OnString 事件:
#[fuchsia::main]
async fn main() -> Result<(), Error> {
// Connect to the Echo protocol, which is assumed to be in the component's environment
let echo = connect_to_protocol::<EchoMarker>().context("Failed to connect to echo service")?;
// Make an EchoString request and wait for the response
let res = echo.echo_string("hello").await?;
println!("response: {:?}", res);
// Make a SendString request
echo.send_string("hi")?;
// Wait for a single OnString event
let EchoEvent::OnString { response } =
echo.take_event_stream().next().await.context("error receiving events")??;
println!("Received OnString event for string {:?}", response);
Ok(())
}
方法是從用戶端物件擷取事件串流,然後等待串流中的單一事件。
執行用戶端
如要讓用戶端和伺服器使用 Echo 通訊協定進行通訊,元件架構必須將 fuchsia.examples.Echo 能力從伺服器路由至用戶端。本教學課程提供
設定建構作業,以便納入提供的套件,其中包含 echo 領域、伺服器和用戶端:
fx set core.x64 --with //examples/fidl/rust:echo-rust-client建構 Fuchsia 映像檔:
fx build執行
echo_realm元件。這會建立用戶端和伺服器元件例項,並將功能路徑導向:ffx component run /core/ffx-laboratory:echo_realm fuchsia-pkg://fuchsia.com/echo-rust-client#meta/echo_realm.cm啟動
echo_client執行個體:ffx component start /core/ffx-laboratory:echo_realm/echo_client
用戶端嘗試連線至 Echo 通訊協定時,伺服器元件就會啟動。裝置記錄檔中應會顯示類似以下的輸出內容 (ffx log):
[echo_server][][I] Listening for incoming connections...
[echo_server][][I] Received EchoString request for string "hello"
[echo_server][][I] Response sent successfully
[echo_client][][I] response: "hello"
[echo_server][][I] Received SendString request for string "hi"
[echo_server][][I] Event sent successfully
[echo_client][][I] Received OnString event for string "hi"
終止領域元件,停止執行作業並清除元件例項:
ffx component destroy /core/ffx-laboratory:echo_realm