天天看點

RTI_DDS自定義插件開發 3 發送方

本節介紹發送消息的傳輸插件的接口。

收集發送

    當NDDS通過傳輸插件發送消息時,它将為傳輸插件提供一系列緩沖區。 傳輸插件負責将此緩沖區數組連接配接成傳遞的單個消息。 數組中所有緩沖區的連接配接是NDDS希望在傳輸的另一端收到的實際消息。

    傳輸插件的接收端應僅向NDDS提供完整消息,而不是單獨呈現構成消息的每個緩沖區。 是以,在發送端,傳輸插件可以一次将緩沖區數組發送到單個緩沖區,在接收端,它應該等到所有緩沖區都收到完整的消息發送到NDDS之前。

這種方法在NDDS核心和Transport Plugin之間提供了一個處理時間高效的接口。 它避免了NDDS需要額外的副本将消息的子部分合并到一個連續的緩沖區中進行發送。 此方法還允許傳輸插件利用實體傳輸,這些傳輸也提供“收集 - 發送”API,例如IP套接字。

    在底層傳輸機制隻能發送單個緩沖區的情況下,傳輸插件的實作或者需要在發送之前将緩沖區陣列中的緩沖區複制到一個連續的緩沖區中,或者放置一些邏輯來檢測何時所有具有緩沖區的緩沖區已被單獨寄出。

隻有同步發送

    Transport-Plugin API的“發送”調用應該是同步的。 也就是說,當“發送”調用傳回時,NDDS核心可以假設消息已經由插件發送,并且傳遞給“發送”調用的緩沖區數組可以自由地重新使用。

請注意,在多個實時作業系統上進行的性能測試顯示,在發送端使用異步零拷貝方法沒有顯着的性能改進。 一般來說,利用異步發送對于NDDS核心的設計來說要複雜得多,并且目前NDDS不支援。

SendResource概念

    在NDDS可以向目的地發送消息之前,NDDS必須确定哪個傳輸插件能夠發送到目的地(IPv6位址+端口組合)。 它通過使用Transport Plugin“預注冊”目的地來實作。 換句話說,NDDS核心将調用傳輸插件( create_sendresource_srEA() )中的函數來建立NDDS嘗試向目标發送消息之前傳輸需要發送到目标的任何資源。

    傳輸插件應該确定它是否能夠發送到目的地(位址/端口)。 如果可以,那麼插件應該建立或以其他方式初始化所需的任何底層傳輸機制,并将這些結果的句柄作為“SendResource”傳回。 當NDDS稍後嘗試向該目的地發送消息時,NDDS将傳回相同的句柄到傳輸插件。

    對于某些類型的傳輸,插件可能不需要做任何不同的事情發送到不同的目的地。 在這種情況下,插件可能能夠在多個目的地共享相同的SendResource。 是以,每當NDDS找到一個Transport Plugin的新目的地時,它将周遊一個Transport Plugin的現有SendResources,并通過調用create_sendresource_srEA()來調用share_sendresource_srEA()嘗試共享一個SendResource,然後建立一個新的SendResource。

    NDDS發現傳輸插件的新目的地時的一個示例是NDDS檢測到在本地DDS DataWriter的遠端應用程式中建立了新的DDS DataReader。

    當NDDS确定它不需要通過特定傳輸插件發送到特定目标時,例如,如果DataReader在遠端應用程式中被銷毀,則NDDS将通知傳輸插件目标不再被任何呼叫使用destroy_sendresource_srEA() unshare_sendresource_srEA()或destroy_sendresource_srEA()與發送源連結到目标。 究竟調用哪個函數是由SendResource是否在多個目的地共享。

   什麼破壞或取消共享SendResource意味着特定的Transport-Plugin實作完全取決于實作。 它可以是關閉套接字并釋放相關資源而不做任何事情的任何東西。

   為了了解NDDS多久嘗試為一個Transport Plugin的特定執行個體共享或建立一個SendResource的想法,請考慮一個簡單的NDDS應用程式和一個參與者(下面的讨論假定您熟悉DDS概念并了解NDDS應用程式的一些知識發現工作并配置)。

    然後,對于對等定位器清單中的所有對等項,其位址可由傳輸器提供服務(必須與傳輸插件具有相同的網絡位址,請參閱傳輸插件中的尋址 ),NDDS将嘗試共享/建立SendResource(因為它會嘗試發送消息到該對等體)。

    另外,對于發現的任何對等點(實際上是活動的并且已經交換了消息),NDDS将從對等點接收到應用程式應發送RTPS中繼資料包的接口/端口清單。 是以,對于Transport Plugin可以通路的任何遠端對等接口,NDDS将嘗試共享/建立該插件的SendResource。

    然後,在發現完成後,當NDDS發現與本地DataWriters比對的遠端DataReader時,它将收到應該用于将資料發送到遠端DataReader的接口/端口組合清單。 同樣,對于可由Transport Plugin提供服務的任何接口,NDDS将嘗試共享/建立該插件的SendResource。

    是以,在最簡單的應用程式中,DataWriter在另一個應用程式中具有比對的DataReader,假設兩個應用程式隻有一個管理單個接口的傳輸插件,NDDS将嘗試共享/建立2個SendResource; 一個用于中繼資料流量,另一個用于使用者資料流量。 如果傳輸插件可以共享相同的SendResource以實作中繼資料流量和使用者資料流量,則實際建立的SendResources數量可能隻有1個。

    NDDS會要求Transport Plugin共享/建立更多的SendResource,因為它發現更多的對等應用程式,因為存在更多比對的DataWriter / DataReader對,或者如果最終使用者将應用程式配置為使用多點傳播位址或指定DataReaders的端口以接收除預設端口。

    NDDS隻會要求傳輸插件為新的唯一位址/端口組合共享/建立新的SendResource,以便傳輸插件實作永遠不會被要求共享或建立已經共享或建立的位址/端口的SendResource一個SendResource。

發送多個接口

    當NDDS調用send() ,它将嘗試發送消息到特定的目标(位址/端口)。 對于管理多個接口的傳輸插件(參見網絡接口 ),可能會出現應該使用哪個接口的問題。 除非目标是多點傳播消息,否則插件通常應該隻選擇一個接口來發送消息。

    例如,IP插件發送的UDP資料包通常會被作業系統的IP堆棧路由,是以它隻能從多NIC系統中的單個接口發送出去。 通常,路由表确定哪個接口用于哪個目的位址。

    是以,雖然每個傳輸插件實作可能有不同的方式來處理多個接口(其中的細節可由最終使用者配置),但通常具有單點傳播目标的消息通過單個接口發送。 但是,實作可能選擇通過多個接口備援發送單點傳播消息。 另外,由于具有多點傳播位址的消息應該被監聽多點傳播位址的所有遠端接口接收,是以傳輸插件應該通過支援多點傳播的所有接口發送多點傳播消息。

    雖然NDDS核心旨在正确處理重複消息(如果通過多個接口或甚至不同傳輸插件接收到相同的消息,則會發生這種情況),但實作者應該知道額外資源(CPU)将被消耗處理重複的消息。 另外,根據時間的不同,由于重複的消息,NDDS可能會不必要地産生(并處理)額外的中繼資料流量。

在接收器初始化之前發送面向連接配接的傳輸

    在建構面向連接配接的傳輸層之上建立釋出 - 訂閱網絡機制時,存在雞和蛋的問題,這種機制本質上是無連接配接的。 對于一個應用程式将資料釋出到另一個應用程式,它需要知道其他應用程式已訂閱了其資料。 但首先,該訂閱的知識必須由訂閱應用程式發送到釋出應用程式。 哪個應用程式首先應該連接配接到另一個? 釋出應用程式或訂閱應用程式? 等等,是不是允許NDDS應用程式既是釋出者又是訂閱者?

    對于無連接配接傳輸而言,這不是什麼大問題。 無需先建立連接配接,即可發送資訊。 是以,即使沒有其他應用程式準備好接收消息, create_sendresource_srEA()和send()調用也可以成功。 是以,在發送資訊之前不需要建立連接配接。 如果接收應用程式啟動,則它将接收資料。 如果它沒有啟動或準備就緒,則資料丢失,并且将由發送應用程式重新發送資訊。

    在面向連接配接的傳輸中,通常在連接配接建立之前無法發送。 在Transport-Plugin API中,對于面向連接配接的傳輸,與特定目标的連接配接将通常在create_sendresource_srEA()調用中建立。 但是,由于應用程式是異步啟動的,是以在第一個應用程式中調用create_sendresource_srEA()時,目标應用程式可能尚未啟動或尚未完成連接配接。

    是以,當create_sendresource_srEA()傳回時,發送方和接收方應用程式之間的連接配接可能尚未完全初始化(連接配接未建立)。 如果是這種情況,則面向連接配接的傳輸插件的create_sendresource_srEA()調用不得傳回失敗代碼。 create_sendresource_srEA()隻應該傳回失敗,如果插件确定沒有可能的方式使用插件發送到給定的目标,而不僅僅是因為它不能建立連接配接。

    如果連接配接無法通過create_sendresource_srEA()建立,它仍然應該建立并傳回一個SendResource給NDDS。 SendResource應該包含某種訓示,表明它沒有完全初始化,也就是說,與接收應用程式的連接配接還沒有建立。

    然後,當NDDS需要使用SendResource發送消息到目的地時,它将通過Transport Plugin的send()指令中的部分初始化的SendResource。 對于面向連接配接的傳輸, send()調用必須檢查與SendResource相關的連接配接是否完全建立。 如果沒有, send()調用本身應該在發送之前嘗試建立連接配接。 可能是到目的地的連接配接仍然無法建立(目标應用程式仍未準備好接受連接配接)。 在這種情況下, send()應該傳回0以表示沒有消息實際發送。

    對于所有的意圖和目的,NDDS将把這種情況看作是由插件發送的消息以某種方式被丢棄。 NDDS将調用傳輸插件的send()函數來再次發送消息。 是以,Transport Plugin将定期有機會與目标應用程式建立連接配接。 假設接收應用程式最終啟動,那麼當send()被NDDS調用時,插件最終會建立連接配接并發送消息。

通過這種方式,NDDS可以使用面向連接配接的傳輸,而獨立于傳輸的哪一邊被首先初始化。

繼續閱讀