RFC-0023:通訊協定的組合模型

RFC-0023:通訊協定的組成模型
狀態已接受
區域
  • FIDL
說明

關鍵字介面由關鍵字通訊協定取代。延伸通訊協定已進一步說明構成模型的組成模型,其中一種通訊協定可以定義為一組訊息,並透過一或多種其他通訊協定擴增。通訊協定擴充功能使用的語法已變更,變更為類似混合使用的語法。

作者
提交日期 (年/月)2018-12-10
審查日期 (年/月)2019-01-09

摘要

我們建議進行下列變更:

  • 關鍵字「介面」會替換為關鍵字「通訊協定」。 (我們會在本文件的其餘部分使用「通訊協定」一詞)。
  • 擴充通訊協定會清楚說明一個「組合模型」,其中一種通訊協定可以定義為一組訊息,並透過一或多個其他通訊協定擴增。
  • 通訊協定擴充功能使用的語法已從「沿用」變更為類似「mixins」的語法。
  • 繫結作者在呈現以目標語言撰寫的通訊協定時,必須避免假設 (例如「is-a」階層、繼承、子類型)。

提振精神

「介面」一詞具有關聯行李,例如方法超載、建構函式和解構函式,以及做為訊息收件者的物件模型等。

不過,FIDL 的目標較為簡單,旨在說明兩個對等點之間的「通訊協定」,也就是一組可交換的訊息。

我們以清楚明瞭的方式啟動 FIDL API,並註明以下執行個體:「雖然語法類似於物件導向介面的定義,設計注意事項比物件系統更接近網路通訊協定」。當我們推出更多「物件導向型」功能的選項時,我們已排除此類功能 (例如最近在 RFC-0020: Ordinal Hashing 上有關超載的註解)。

我們希望使用者能在語言更清楚瞭解這項差異,因此建議您將關鍵字 interface 替換為關鍵字 protocol,藉此改變語法。

此外,借用繼承語法隱含的「is-a」關係也會導致錯誤,並導致要求不正確。(為求明確,FIDL 並未提供這類繼承語意,但語法建議盡可能顯示)。 詳情請參閱「屬於 A」關係視為有害關係一節。

設計

本提案導入正式語意,描述程序互動和通訊協定。

本提案會變更 FIDL 來源語言,以釐清通訊協定擴充功能的語意,並提供繫結作者的新指南。

JSON IR 目前不會顯示繼承關係,因此繫結作者無法使用這些關係。因此,除了改良的說明文件,我們預計對新指南修改產生的繫結程式碼的方式幾乎不會有所改變。

此提案不會變更傳輸格式。

本提案並不會變更 JSON IR,但我們預期會在未來進行較大的變更時加入鍵名重新命名。

通訊協定模型

Zircon 管道隨其所攜帶的酬載不需要特定結構定義。FIDL 是以這個原始技術為基礎,並會限制管道傳輸特定通訊協定。因此,FIDL 會為管道兩端賦予定義和名稱。 我們會呼叫「用戶端」和「伺服器」

我們的模型將一種通訊協定描述為一組有向互動,並搭配選用的 epitaph。我們會使用通訊協定,在用戶端和伺服器之間通訊的特定執行個體稱為「工作階段」

方向可以是「從用戶端到伺服器」,或「從伺服器到用戶端」

互動是以「要求」為開頭,可能會視需要要求回應。回應無回應的互動通常使用「啟動後忘記」或「單向」一詞,而「呼叫」一詞則代表預期回應的要求。

要求和回應都是以標頭表示的「訊息」,後接結構的酬載,即要求或回應的「引數」

目前 Google 會限制伺服器對用戶端訊息的回應。 簡單來說,「事件只會觸發而忘記」。

「epitaph」是指結束工作階段的伺服器對用戶端互動。詳情請參閱 RFC-0053: Epitaphs

這個模型缺少部分互動較為複雜,例如三向握手握住 TCP 的 SYN/SYN-ACK/ACK。我們會視為超出範圍,因此未來模型的調整作業可能也不會涵蓋這些變動。

組合模型

目前,通訊協定可以定義互動以及擴充一或多個通訊協定。產生的通訊協定 (「組合通訊協定」) 會保存直接定義的所有互動,並繼承子項 (直接或間接) 定義的所有互動。

例如,Child 通訊協定定義為:

protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child { compose Parent1; compose Parent 2; Method3(); };

這三項互動可能會是 Method1Method2Method3

不過,無論 Method1Method2 是因組合而在 Child 中定義,還是直接傳遞至特定語言的後端,也就是說,JSON IR 中不會呈現這項資訊。

「是」人際關係受到傷害

由於通訊協定可以雙向傳送要求,因此要建立子關係就要格外小心。因此,我們不允許通訊協定與其擴充的通訊協定進行「是」關係。

例如,假設有兩個通訊協定:

protocol Parent { Method(); };
protocol Child { ->Event(...); };

我們允許採用通訊協定 Child 的管道視為 Parent(即「Child」與「Parent」的關係),但我們會公開用戶端無法接收的 Event 帳號代碼。 如需具體範例,請參閱下一節

我們將設法支援特定的通訊協定註解 (例如「僅限用戶端對伺服器互動」),以支援並允許「是」關係。發生這種情況時,這類關係會用於 JSON IR,以便使用後端。

現今對「是」人際關係的依賴

這裡列舉一個具體範例,fuchsia.media 程式庫將多個通訊協定組合在一起。 請特別注意以下幾點:

AudioCapturerAudioRenderer 沒有定義事件,例如在用戶端對伺服器通訊協定中,這些通訊協定完全是單向的。(StreamSource 定義了兩個事件,但我們在此特別討論每種通訊協定本身的定義)。

因此,如果用戶端知道如何與 StreamBufferSetStreamSource (分別為 StreamBufferSetStreamSink) 互動,也可以分別與 AudioCapturerAudioRenderer 互動,也就是用戶端會直接忽略公開的額外方法。我們可以在這裡定義「是」關係。

不過,如果將事件新增至任一介面,這項「是」關係就會停止。假設用戶端與 StreamBufferSet 互動,也就是伺服器端的 AudioRenderer。如果 AudioRenderer 觸發事件,會發生什麼事? 這時該客戶會如何處理?

由於我們 (尚) 無法在 fidlc 中提供區別,因此我們確認並未支援「是」關係。本提案基本上會闡明現狀。

如同 fuchsia.media 的例子,知道特定關係為真實的作者可以根據需求繫結繫結 (使用轉換等)。

在後續的提案中,我們預計要加入屬性或新關鍵字來擷取這項方向限制,並根據上述內容在繫結中提供「是」關係。在提出這些提案之前,我們無法在 FIDL 工具鍊中提供更好的支援。

語法變更

在設計階段,我們提議了幾種不同的替代方案,請參閱下方的「缺點、替代方案和未知

使用可接受語法的擴充通訊協定,如下所示:

protocol Parent1 {
  Method1OfParent1();
  Method2OfParent1();
};

protocol Parent2 {
  Method1OfParent2();
  Method2OfParent2();
};

protocol Child {
  compose Parent1;
  compose Parent2;
  Method1OfChild();
  Method2OfChild();
};

文法的正式變更如下:

declaration = const-declaration | enum-declaration | protocol-declaration |
              struct-declaration | union-declaration | table-declaration ;

protocol-declaration = ( attribute-list ) , "protocol" , IDENTIFIER ,
                       "{" , ( method-or-compose-declaration , ";" )*  , "}";

method-or-compose = method-declaration | compose-declaration ;

method-declaration = ( ordinal , ":" ) , method-parameters ;

method-parameters = IDENTIFIER , parameter-list , ( "->" , parameter-list )
                     | "->" , IDENTIFIER , parameter-list ;

compose-declaration = "compose", compound-identifier ;

一個組成的通訊協定只能提及一次。

可能的額外資訊

我們預期在後續提案中會額外允許伺服器用戶端與需要回應的互動,進而在管道上啟用多工通訊協定 (可能以反向順序排列)。例如,執行個體 coordinator.fidl 定義了兩個指令回應通訊協定,一個來自 devmgr -> devhost,另一個來自 devhost -> devmgr。目前這些程序是以手動方式進行多工處理,並仰賴序數分派來找出確切的分派程度。

我們可能會在撰寫區塊中使用「->」語法,稍後再導入多工處理 (反向方向)。另一個替代方案是,當擴充功能包含反向通訊協定時,只需要明確方向,這樣便不適合導入任何方向語法,因為我們延後採用反向通訊協定的擴充功能。

我們允許將 Compose 區塊放在通訊協定定義中的任何位置,也允許多個 Compose 區塊。我們可能只有一個區塊,且可能必須將該區塊置於頂端。在這個例子中,我們選擇開放式的,而非仰賴自動格式和/或樣式指南來提供建議,而非根據語言本身所做出的違規處置。

JSON IR

本次異動不會變更 JSON IR。

而是在進行更多變更時,將「interface_declarations」金鑰重新命名為「protocol_declarations」。這一系列的變更將需要採取多個步驟,將結構定義版本從 0.0.1 改用 0.0.2,且後端有適應期。

距離中斷現象,並使用 [FragileBase]

此提案不會影響距離連線可能中斷的狀態,因此針對擴充的任何通訊協定,我們再次確認使用 [FragileBase]1

繫結作者指南

  • 繫結必須避免假設 (例如「is-a」階層、繼承、子類型),以目標語言表示組合的通訊協定。
  • 而是接收不明序數的錯誤。繫結應顯示為「不明序數錯誤」,並關閉管道。

導入策略

三個步驟:

  1. 新增對新語法的支援;
  2. 將所有 FIDL 檔案轉換成使用新語法;
  3. 放棄使用舊語法。

人體工學

這項變更可讓 FIDL 更清楚瞭解,請參閱「動機」一節。 這項變更可能無法讓 FIDL 一開始就更容易理解,但可避免對路上造成誤解,以及不一致的期望。

說明文件與範例

我們需要更新語言、文法、評分量表和其他相關文件。

回溯相容性

這項變更會破壞目前使用繼承的 FIDL 檔案來源相容性。 如實作中所述,我們將分階段導入新語法並遷移所有 FIDL 檔案,然後移除對舊語法的支援。

這項變更不會變更 FIDL 傳輸格式,因此是回溯相容的 ABI 變更。

效能

不影響效能。

安全性

或許我們能運用更嚴格的輸入語意來保護頻道或觀察管道。 這並非本提案的目標,並未影響現狀,可說是能提升現狀。

測試

這項變更可以完全透過單元測試在 fidlc 層級完成。

缺點、替代方案和未知

以下各節記錄設計階段提議的替代語法。

替代語法 (pascallouis@)

範例

protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child {
  compose {
    -> Parent1();
    -> Parent2();
  };
  Method1OfChild();
}

注意:這是原始提議的語法。導致 compose 區塊看起來不自然,而且與原本存在的語言混淆過多。這會讓撰寫多個通訊協定的偏好方法,而以撰寫單一的感覺較為詳細。此外,我們還不確定是否允許多個 compose 區塊,以及運作方式。最後,我們選擇避免在通訊協定上使用定向「->」指標,而該指標傾向於循序漸進進行多方向多工處理 (如果這類功能曾列入考慮)。

替代語法 (jeremymanson@)

原因:以下說明應實作的方法清單與定義通訊協定的方法清單之間的差異:

範例

protocol Parent1 {
  Method1OfParent1();
  Method2OfParent1();
};

protocol Parent2 {
  Method1OfParent2();
  Method2OfParent2();
};

interface Child {
  compose {
    -> Parent1();
    -> Parent2();
  };
  Method1OfChild();
};

注意:「介面」關鍵字表示每個方法都必須具備實作項目,「通訊協定」關鍵字則用於表示所有整合通訊協定和介面的相關規定。我們不見得會預期 StreamSource 有專屬的實作方式。因此我們可以進一步沿用實作方式,明確指出沒有任何影響。 您無法將介面組合成其他介面。

替代語法:類似介面的介面組合 (proppy@)

原因:看起來與嵌入介面有非繼承和熟悉 Golang 語法

範例

protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child {
    Parent1;
    Parent2;
    Method3();
};

注意:介面和嵌入功能的 Go 語言spec

替代語法:使用宣告 (jeffbrown@)

原因:看起來不會像繼承,而是重複使用現有關鍵字,以指出納入範圍的名稱。 較不可能與方法宣告或「屬性2」混淆。

範例

protocol Parent1 { Method1(); };
protocol Parent2 { Method2(); };
protocol Child {
    using Parent1;
    using Parent2;
    Method3();
};

注意:FIDL、C++、Rust 和其他語言的前置字元。

替代關鍵字

compose」關鍵字的替代選項:

  • extends (pascallouis@)
  • contains (smklein@)

先前的圖片和參考資料

無所謂,

Cap'n Proto 具有支援繼承的介面,包括多重繼承 (混合樣式)。


  1. 我們在日後提案中引進了適用於方法的 Ordinal 雜湊,加上將 32 位元到 64 位元的預定方法序數,而這可能會在存在距離 (實際上是實際做法) 下中斷,並再次審視 FragileBase 的用法。

  2. 屬性:用於協助觀測 / 資料繫結的假想 FIDL 擴充功能。簡單來說,繫結會產生用於存取、修改和/或觀察介面公開的值的方法。