通訊協定處理常式是一個已知的物件,可以提供 使用元件命名空間探索的 FIDL 通訊協定。元件 這個架構有助於在 元件 科技往往有多種不同用途 功能轉送功能會說明哪些元件應做為供應商的供應者 指定的用戶端。找出適當的元件後 元件管理員 會使用每個路徑中的控點來啟動元件之間的連結 元件的命名空間
請參考以下範例的 fuchsia.example.Foo
通訊協定:
此圖表醒目顯示與執行連線相關的主要元素:
- 提供者元件會以靜態方式「通訊協定」
資訊清單的
capabilities
部分。這樣就能啟用元件架構 執行能力轉送 - 用戶端元件會以靜態方式要求
use
區段中的通訊協定 資訊清單這會建立/svc/fuchsia.example.Foo
通訊協定項目 呼叫。 - 供應商程式碼會在執行階段發布實作內容。這會建立
供應器傳出
/svc/fuchsia.example.Foo
的通訊協定項目 目錄。 - 用戶端程式碼會在執行階段連線至通訊協定控制代碼。這會開啟 FIDL 連線,連至在提供者元件中執行的實作。
發布通訊協定實作
實作 FIDL 通訊協定的元件會宣告並公開 作為元件資訊清單中的能力這會啟用元件 從這個元件到 要求這些能力的拓撲
{
// ...
capabilities: [
{ protocol: "fuchsia.example.Foo" },
],
expose: [
{
protocol: "fuchsia.example.Foo",
from: "self",
},
],
}
功能轉送可用來說明通訊協定的存取權限,但確實會
未建立連線所需的端點。元件必須發布
使用/svc/
fuchsia.io 通訊協定。
產生的 FIDL 繫結會包裝這個帳號代碼,讓供應器能夠
要求控制代碼開始接收 FIDL 訊息。
荒漠油廠
let mut service_fs = ServiceFs::new_local();
// Serve the protocol
service_fs.dir("svc").add_fidl_service(PROTOCOL_NAME);
service_fs.take_and_serve_directory_handle().context("failed to serve outgoing namespace")?;
C++
// Serve the protocol
FooImplementation instance;
fidl::Binding<fuchsia::example::Foo> binding(&instance);
instance.event_sender_ = &binding.events();
fidl::InterfaceRequestHandler<fuchsia::example::Foo> handler =
[&](fidl::InterfaceRequest<fuchsia::example::Foo> request) {
binding.Bind(std::move(request));
};
context->outgoing()->AddPublicService(std::move(handler));
連線到通訊協定實作
用戶端元件會在各自的程式碼中,宣告該通訊協定為必要能力
元件資訊清單。如此一來,元件架構就能判斷
元件有權存取通訊協定實作。如果路徑有效
,元件的命名空間會包含對應的 /svc/
控制代碼。
{
// ...
use: [
{ protocol: "fuchsia.example.Foo" },
],
}
用戶端元件會使用 fuchsia.io 通訊協定連線至 建立連至通訊協定實作的連線,並開啟管道。 產生的 FIDL 繫結會納入這個管道,讓用戶端開始傳送 訊息傳送給供應商。
荒漠油廠
// Connect to FIDL protocol
let protocol = connect_to_protocol::<FooMarker>().expect("error connecting to echo");
C++
// Connect to FIDL protocol
fuchsia::example::FooSyncPtr proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(proxy.NewRequest());
練習:Echo 伺服器和用戶端
在本節中,您將使用產生的 FIDL 繫結:
fidl.examples.routing.echo
,用於在 Rust 中實作用戶端和伺服器元件。
啟動模擬器
如果您還沒有執行中的執行個體,請啟動模擬器:
啟動新的模擬器執行個體:
ffx emu start --headless
啟動完成後,模擬器會顯示下列訊息並 會傳回:
Logging to "$HOME/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log" Waiting for Fuchsia to start (up to 60 seconds)........ Emulator is ready.
啟動套件伺服器,讓模擬器載入軟體套件:
fx serve
建立伺服器元件
首先,請建立新的元件專案來實作 echo 伺服器。這個
元件將提供 Echo
通訊協定並處理傳入要求。
為名為 echo-server
的新元件建立專案 Scaffold
//vendor/fuchsia-codelab
目錄:
mkdir -p vendor/fuchsia-codelab/echo-server
在新的專案目錄中建立以下檔案和目錄結構:
荒漠油廠
//vendor/fuchsia-codelab/echo-server
|- BUILD.gn
|- meta
| |- echo.cml
|
|- src
|- main.rs
C++
//vendor/fuchsia-codelab/echo-server
|- BUILD.gn
|- meta
| |- echo.cml
|
|- main.cc
將下列建構規則新增至 BUILD.gn
檔案,即可建構並套件伺服器元件:
荒漠油廠
echo-server/BUILD.gn
:
import("//build/components.gni")
import("//build/rust/rustc_binary.gni")
rustc_binary("bin") {
output_name = "echo-server"
edition = "2021"
deps = [
"//vendor/fuchsia-codelab/echo-fidl:echo_rust",
"//src/lib/diagnostics/inspect/runtime/rust",
"//src/lib/diagnostics/inspect/rust",
"//src/lib/fuchsia",
"//src/lib/fuchsia-component",
"//third_party/rust_crates:anyhow",
"//third_party/rust_crates:futures",
]
sources = [ "src/main.rs" ]
}
# Unpackaged component "#meta/echo_server.cm"
fuchsia_component("echo_server_cmp") {
component_name = "echo_server"
manifest = "meta/echo_server.cml"
deps = [ ":bin" ]
}
fuchsia_package("echo-server") {
package_name = "echo-server"
deps = [ ":component" ]
}
C++
echo-server/BUILD.gn
:
import("//build/components.gni")
executable("bin") {
output_name = "echo-server"
sources = [ "main.cc" ]
deps = [
"//vendor/fuchsia-codelab/echo-fidl:echo_hlcpp",
"//sdk/lib/async-loop:async-loop-cpp",
"//sdk/lib/async-loop:async-loop-default",
"//sdk/lib/inspect/component/cpp",
"//sdk/lib/sys/cpp",
]
}
# Unpackaged component "#meta/echo_server.cm"
fuchsia_component("echo_server_cmp") {
component_name = "echo_server"
manifest = "meta/echo_server.cml"
deps = [ ":bin" ]
}
fuchsia_package("echo-server") {
package_name = "echo-server"
deps = [ ":component" ]
}
將 Echo
通訊協定宣告為伺服器元件提供的能力。
然後公開供父項領域使用:
荒漠油廠
echo-server/meta/echo_server.cml
:
{
include: [
"inspect/client.shard.cml",
"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/echo-server",
},
// Capabilities provided by this component.
capabilities: [
{ protocol: "fidl.examples.routing.echo.Echo" },
],
expose: [
{
protocol: "fidl.examples.routing.echo.Echo",
from: "self",
},
],
}
C++
echo-server/meta/echo_server.cml
:
{
include: [
"inspect/client.shard.cml",
"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/echo-server",
},
// Capabilities provided by this component.
capabilities: [
{ protocol: "fidl.examples.routing.echo.Echo" },
],
expose: [
{
protocol: "fidl.examples.routing.echo.Echo",
from: "self",
},
],
}
實作伺服器
開啟主要來源檔案,並將匯入陳述式替換為 下列程式碼:
荒漠油廠
echo-server/src/main.rs
:
use anyhow::Context;
use fidl_fidl_examples_routing_echo::{EchoRequest, EchoRequestStream};
use fuchsia_component::server::ServiceFs;
use fuchsia_inspect::component;
use fuchsia_inspect::health::Reporter;
use futures::prelude::*;
C++
echo-server/main.cc
:
#include <fidl/examples/routing/echo/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/inspect/component/cpp/component.h>
#include <lib/sys/cpp/component_context.h>
將下列程式碼新增至 main()
以提供 Echo
通訊協定:
荒漠油廠
echo-server/src/main.rs
:
// Wrap protocol requests being served.
enum IncomingRequest {
Echo(EchoRequestStream),
}
#[fuchsia::main(logging = false)]
async fn main() -> Result<(), anyhow::Error> {
let mut service_fs = ServiceFs::new_local();
// Initialize inspect
component::health().set_starting_up();
let _inspect_server_task = inspect_runtime::publish(
component::inspector(),
inspect_runtime::PublishOptions::default(),
);
// Serve the Echo protocol
service_fs.dir("svc").add_fidl_service(IncomingRequest::Echo);
service_fs.take_and_serve_directory_handle().context("failed to serve outgoing namespace")?;
// Component is serving and ready to handle incoming requests
component::health().set_ok();
// Attach request handler for incoming requests
service_fs
.for_each_concurrent(None, |request: IncomingRequest| async move {
match request {
IncomingRequest::Echo(stream) => handle_echo_request(stream).await,
}
})
.await;
Ok(())
}
這段程式碼會執行下列步驟,提供 Echo
通訊協定:
- 初始化
ServiceFs
並在下方新增項目 傳出目錄的/svc/fidl.examples.routing.echo.Echo
。 - 提供目錄,並開始監聽傳入連線。
- 附加
handle_echo_request()
函式,以做為任何要求處理常式的要求處理常式 相符的Echo
項要求。
C++
echo-server/main.cc
:
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
// Initialize inspect
inspect::ComponentInspector inspector(loop.dispatcher(), inspect::PublishOptions{});
inspector.Health().StartingUp();
// Serve the Echo protocol
EchoImplementation echo_instance;
fidl::Binding<fidl::examples::routing::echo::Echo> binding(&echo_instance);
echo_instance.event_sender_ = &binding.events();
fidl::InterfaceRequestHandler<fidl::examples::routing::echo::Echo> handler =
[&](fidl::InterfaceRequest<fidl::examples::routing::echo::Echo> request) {
binding.Bind(std::move(request));
};
context->outgoing()->AddPublicService(std::move(handler));
// Component is serving and ready to handle incoming requests
inspector.Health().Ok();
return loop.Run();
}
這段程式碼會執行下列步驟,提供 Echo
通訊協定:
- 初始化
ComponentContext
並在下方新增項目 傳出目錄的/svc/fidl.examples.routing.echo.Echo
。 - 提供目錄,並開始監聽傳入連線。
- 將
EchoImplementation
執行個體附加為任意要求處理常式的要求處理常式 相符的Echo
項要求。
新增下列程式碼,實作通訊協定要求處理常式:
荒漠油廠
echo-server/src/main.rs
:
// Handler for incoming service requests
async fn handle_echo_request(mut stream: EchoRequestStream) {
while let Some(event) = stream.try_next().await.expect("failed to serve echo service") {
let EchoRequest::EchoString { value, responder } = event;
responder.send(value.as_ref().map(|s| &**s)).expect("failed to send echo response");
}
}
EchoRequestStream
中的每個要求都可以依方法名稱類型輸入
(EchoString
),並包含可傳回回傳值的作答者介面。
C++
echo-server/main.cc
:
// Handler for incoming service requests
class EchoImplementation : public fidl::examples::routing::echo::Echo {
public:
void EchoString(fidl::StringPtr value, EchoStringCallback callback) override { callback(value); }
fidl::examples::routing::echo::Echo_EventSender* event_sender_;
};
每個 Echo
通訊協定方法都有對應的覆寫函式
(EchoString()
),其中包含可傳回傳回值的回呼介面。
這項實作會直接「echo」與來自請求來源的相同字串值 回應酬載中的錯誤。
建立用戶端元件
建立另一個新元件專案以實作 echo 用戶端。這個 元件將連線至通訊協定實作並傳送要求。
為名為 echo-client
的新元件建立專案 Scaffold
//vendor/fuchsia-codelab
目錄:
mkdir -p vendor/fuchsia-codelab/echo-client
在新的專案目錄中建立以下檔案和目錄結構:
荒漠油廠
//vendor/fuchsia-codelab/echo-client
|- BUILD.gn
|- meta
| |- echo.cml
|
|- src
|- main.rs
C++
//vendor/fuchsia-codelab/echo-client
|- BUILD.gn
|- meta
| |- echo.cml
|
|- main.cc
將下列建構規則新增至 BUILD.gn
檔案,即可建構及套件用戶端元件:
荒漠油廠
echo-client/BUILD.gn
:
import("//build/components.gni")
import("//build/rust/rustc_binary.gni")
rustc_binary("bin") {
output_name = "echo-client"
edition = "2021"
deps = [
"//vendor/fuchsia-codelab/echo-fidl:echo_rust",
"//src/lib/fuchsia",
"//src/lib/fuchsia-component",
"//third_party/rust_crates:anyhow",
"//third_party/rust_crates:tracing",
]
sources = [ "src/main.rs" ]
}
# Unpackaged component "#meta/echo_client.cm"
fuchsia_component("echo_client_cmp") {
component_name = "echo_client"
manifest = "meta/echo_client.cml"
deps = [ ":bin" ]
}
fuchsia_package("echo-client") {
package_name = "echo-client"
deps = [ ":component" ]
}
C++
echo-client/BUILD.gn
:
import("//build/components.gni")
executable("bin") {
output_name = "echo-client"
sources = [ "main.cc" ]
deps = [
"//vendor/fuchsia-codelab/echo-fidl:echo_hlcpp",
"//sdk/lib/async-loop:async-loop-cpp",
"//sdk/lib/async-loop:async-loop-default",
"//sdk/lib/sys/cpp",
"//sdk/lib/syslog/cpp",
]
}
# Unpackaged component "#meta/echo_client.cm"
fuchsia_component("echo_client_cmp") {
component_name = "echo_client"
manifest = "meta/echo_client.cml"
deps = [ ":bin" ]
}
fuchsia_package("echo-client") {
package_name = "echo-client"
deps = [ ":component" ]
}
設定用戶端的元件資訊清單以要求
伺服器公開的 fidl.examples.routing.echo.Echo
能力:
荒漠油廠
echo-client/meta/echo_client.cml
:
{
include: [
// Enable logging on stdout
"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/echo-client",
// Program arguments
args: [ "Hello Fuchsia!" ],
},
// Capabilities used by this component.
use: [
{ protocol: "fidl.examples.routing.echo.Echo" },
],
}
C++
echo-client/meta/echo_client.cml
:
{
include: [
// Enable logging.
"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/echo-client",
// Program arguments
args: [ "Hello Fuchsia!" ],
},
// Capabilities used by this component.
use: [
{ protocol: "fidl.examples.routing.echo.Echo" },
],
}
實作用戶端
與 echo-args
類似,用戶端會以訊息的形式傳遞程式引數
傳送到伺服器將下列程式引數新增至 echo_client.cml
:
荒漠油廠
echo-client/meta/echo_client.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/echo-client",
// Program arguments
args: [ "Hello Fuchsia!" ],
},
C++
echo-client/meta/echo_client.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/echo-client",
// Program arguments
args: [ "Hello Fuchsia!" ],
},
開啟主要來源檔案,並將匯入陳述式替換為以下程式碼:
荒漠油廠
echo-client/src/main.rs
:
use fidl_fidl_examples_routing_echo::EchoMarker;
use fuchsia_component::client::connect_to_protocol;
C++
echo-client/main.cc
:
#include <fidl/examples/routing/echo/cpp/fidl.h>
#include <lib/fidl/cpp/string.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <cstdlib>
#include <iostream>
#include <string>
將下列程式碼新增至 main()
,即可連線至 Echo
通訊協定並傳送
要求:
荒漠油廠
echo-client/src/main.rs
:
#[fuchsia::main]
async fn main() -> Result<(), anyhow::Error> {
// Parse arguments, removing binary name
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
// Connect to FIDL protocol
let echo = connect_to_protocol::<EchoMarker>().expect("error connecting to echo");
// Send messages over FIDL interface
for message in args {
let out = echo.echo_string(Some(&message)).await.expect("echo_string failed");
tracing::info!("Server response: {}", out.as_ref().expect("echo_string got empty result"));
}
Ok(())
}
EchoMarker
會提供包裝函式,以透過
並傳回控制代碼至開啟的 EchoProxy
介面。這個 Proxy 含有
echo_string()
FIDL 通訊協定方法。
C++
echo-client/main.cc
:
int main(int argc, const char* argv[], char* envp[]) {
// Set tags for logging.
fuchsia_logging::LogSettingsBuilder builder;
builder.WithTags({"echo_client"}).BuildAndInitialize();
// Connect to FIDL protocol
fidl::examples::routing::echo::EchoSyncPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
// Send messages over FIDL interface for each argument
fidl::StringPtr response = nullptr;
for (int i = 1; i < argc; i++) {
ZX_ASSERT(echo_proxy->EchoString(argv[i], &response) == ZX_OK);
if (!response.has_value()) {
FX_LOG_KV(INFO, "echo_string got empty result");
} else {
FX_LOG_KV(INFO, "Server response", FX_KV("response", response->c_str()));
}
}
return 0;
}
EchoSyncPtr
會提供包裝函式,以透過
並傳回處理常式開啟的 Proxy 介面。這個 Proxy 含有
EchoString()
FIDL 通訊協定方法。
整合元件
伺服器提供的功能必須透過 元件架構如要啟用這項功能,您必須實作領域元件 擔任父項並管理能力轉送
為領域產品定義建立新的專案目錄:
mkdir -p vendor/fuchsia-codelab/echo-realm
在新的專案目錄中建立以下檔案和目錄結構:
//vendor/fuchsia-codelab/echo-realm
|- BUILD.gn
|- meta
| |- echo_realm.cml
建立新的元件資訊清單檔案 meta/echo_realm.cml
,並使用
以下內容:
echo-realm/meta/echo_realm.cml
:
{
// Two children: a server and client.
children: [
{
name: "echo_server",
url: "#meta/echo_server.cm",
},
{
name: "echo_client",
url: "#meta/echo_client.cm",
},
],
offer: [
// Route Echo protocol from server to client.
{
protocol: "fidl.examples.routing.echo.Echo",
from: "#echo_server",
to: "#echo_client",
},
// Route diagnostics protocols to both children.
{
protocol: [
"fuchsia.inspect.InspectSink",
"fuchsia.logger.LogSink",
],
from: "parent",
to: [
"#echo_client",
"#echo_server",
],
},
],
}
這會建立含有伺服器和用戶端的元件領域做為子項元件,並將 fidl.examples.routing.echo.Echo
通訊協定能力轉送至用戶端。
新增 BUILD.gn
檔案,建立領域元件的建構目標:
echo-realm/BUILD.gn
:
import("//build/components.gni")
fuchsia_component("echo_realm") {
manifest = "meta/echo_realm.cml"
}
fuchsia_package("echo-realm") {
deps = [
":echo_realm",
"//vendor/fuchsia-codelab/echo-server:component",
"//vendor/fuchsia-codelab/echo-client:component",
]
}
更新建構設定以包含新元件:
fx set workstation_eng.x64 \
--with //vendor/fuchsia-codelab/echo-server \
--with //vendor/fuchsia-codelab/echo-client \
--with //vendor/fuchsia-codelab/echo-realm
再次執行 fx build
以建構元件:
fx build
將元件新增至拓撲
您必須將元件新增至 ffx-laboratory
(受限制的集合)
用於產品核心領域中的開發作業啟用集合
並在執行階段動態建立及刪除元件
傳送 echo-realm
元件網址和
安裝在 ffx-laboratory
到 ffx component create
中的適當路徑名稱:
ffx component create /core/ffx-laboratory:echo-realm \
fuchsia-pkg://fuchsia.com/echo-realm#meta/echo_realm.cm
然後,使用 ffx component resolve
解析 echo-realm
元件:
ffx component resolve /core/ffx-laboratory:echo-realm
確認伺服器和用戶端的執行個體是否也已建立為子項
使用 ffx component show
的元件:
ffx component show echo
Moniker: /core/ffx-laboratory:echo-realm/echo_client
URL: #meta/echo_client.cm
Type: CML static component
Component State: Unresolved
Execution State: Stopped
Moniker: /core/ffx-laboratory:echo-realm/echo_server
URL: #meta/echo_server.cm
Type: CML static component
Component State: Unresolved
Execution State: Stopped
Moniker: /core/ffx-laboratory:echo-realm
URL: fuchsia-pkg://fuchsia.com/echo-realm#meta/echo_realm.cm
Type: CML dynamic component
Component State: Resolved
Execution State: Stopped
Merkle root: 666c40477785f89b0ace22b30d65f1338f1d308ecceacb0f65f5140baa889e1b
驗證元件互動
使用 ffx component start
啟動現有的用戶端元件執行個體:
ffx component start /core/ffx-laboratory:echo-realm/echo_client
開啟另一個終端機視窗,並確認來自用戶端元件的記錄輸出:
ffx log --filter echo
您應該會在裝置記錄中看到下列輸出內容:
[echo_client][I] Server response: Hello, Fuchsia!
伺服器元件會在用戶端與
fidl.examples.routing.echo.Echo
能力並持續放送
以及額外的 FIDL 要求
使用 ffx component show
,查看在元件中執行的 echo 伺服器
執行個體樹狀結構:
ffx component show echo_server
Moniker: /core/ffx-laboratory:echo-realm/echo_server
URL: #meta/echo_server.cm
Type: CML static component
Component State: Resolved
Incoming Capabilities: fuchsia.logger.LogSink
Exposed Capabilities: diagnostics
fidl.examples.routing.echo.Echo
Execution State: Running
Job ID: 474691
Process ID: 474712
Running for: 2026280474361 ticks
Merkle root: 666c40477785f89b0ace22b30d65f1338f1d308ecceacb0f65f5140baa889e1b
Outgoing Capabilities: diagnostics
fidl.examples.routing.echo.Echo
刪除執行個體
使用下列指令清除 echo-realm
執行個體:
ffx component destroy /core/ffx-laboratory:echo-realm