DBUS是一種高級的進程間通訊機制。DBUS支持進程間一對一和多對多的對等通訊,在多對多的通信時,須要後臺進程的角色去分轉消息,當一個進程發消息給另一個進程時,先發消息到後臺進程,再經過後臺進程將信息轉發到目的進程。DBUS後臺進程充當着一個路由器的角色。node
DBUS中主要概念爲總線,鏈接到總線的進程可經過總線接收或傳遞消息,總線收到消息時,根據不一樣的消息類型進行不一樣的處理。DBUS中消息分爲四類:linux
1. Methodcall消息:將觸發一個函數調用 ;算法
2. Methodreturn消息:觸發函數調用返回的結果;api
3. Error消息:觸發的函數調用返回一個異常 ;網絡
4. Signal消息:通知,能夠看做爲事件消息。session
根據DBUS消息類型可知,DBUS提供一種高效的進程間通訊機制,主要用於進程間函數調用以及進程間信號廣播。數據結構
1 . 函數調用多線程
DBUS能夠實現進程間函數調用,進程A發送函數調用的請求(Methodcall消息),通過總線轉發至進程B。進程B將應答函數返回值(Method return消息)或者錯誤消息(Error消息)。架構
2 . 消息廣播併發
進程間消息廣播(Signal消息)不須要響應,接收方須要向總線註冊感興趣的消息類型,當總線接收到「Signal消息」類型的消息時,會將消息轉發至但願接收的進程。
DBUS是一種低延遲、低開銷、高可用性的進程間通訊機制。其協議是二進制的,避免序列化的過程,通訊效率較高。DUBUS能夠提供一些更高層的功能:
1. 結構化的名字空間;
2. 獨立於架構的數據格式;
3. 支持消息中的大部分通用數據元素;
4. 帶有異常處理的通用遠程調用接口;
5. 支持廣播類型的通訊。DBUS是一種高級的IPC通訊機制,通訊流程如圖 2‑1所示。在DBUS通訊過程當中,存在一個後臺進程(BUS Daemon Process)。後臺進程和普通進程間信息交互是經過域套接字進行通訊。
如圖 2‑1所示,進程1(Process1)需先鏈接到總線(dbus_bus_get),其次構造消息(dbus_message_new_signal),而後發送消息(dbus_connection_send)到後臺進程。後臺進程接收消息,而後根據消息類型對消息進行不一樣處理(bus_dispatch_matches)。
進程2(Process2)接收消息前須要鏈接到總線,並告知總線本身但願獲得的消息類型(dbus_bus_add_match),而後等待接收消息(dbus_connection_pop_message)。進程2(Process2)收到總線轉發的消息時會根據消息類型,作不一樣的處理(如果信號類型則不須要發送返回值給總線)。
進程間通訊前,須要鏈接到總線。調用dbus_bus_get函數鏈接進程到總線,創建進程和總線之間的鏈接(DBusConnection)。創建鏈接後,須要爲這個鏈接註冊名稱,方便後面對這個鏈接進行操做,調用dbus_bus_request_name函數對鏈接進行註冊名稱。
創建鏈接和註冊名稱是在程序開始時執行,程序結束時,調用dbus_connection_close函數關閉一個鏈接。函數接口聲明如程序清單 2‑1所示。
程序清單 2-1 創建、註冊名稱和關閉鏈接
DBUS中信號是一種廣播的消息,當發出一個信號,全部鏈接到 DBUS 總線上並註冊了接受對應信號的進程,都會收到該信號。
進程發出一個信號前,須要建立一個 DBusMessage 對象來表明信號,而後追加上一些須要發出的參數,就能夠發向總線了。發完以後須要釋放消息對象。信號發送的函數聲明如程序清單 2‑2所示。調用一個遠程函數與發送一個信號原理相似,須要先建立一個消息(DBusMessage),而後經過註冊在 DBUS上的名稱指定發送的對象。而後追加相應的參數,調用方法分爲兩種,一種是阻塞式的,另外一種爲異步調用。異步調用的時候會獲得一個「DBusMessage *」 類型的返回消息,從這個返回消息中能夠獲取一些返回的參數。
函數調用的函數聲明如程序清單 2‑4所示。DBUS是一種高效、易用的進程間通訊方式。本文檔介紹了DBUS的通訊原理,以信號收發和方法調用爲框架,介紹了DBUS中經常使用的函數接口。
DBus分爲兩種類型:system bus(系統總線),用於系統(Linux)和用戶程序之間進行通訊和消息的傳遞;session bus(回話總線),用於桌面(GNOME, KDE等)用戶程序之間進行通訊。
上節補存:
Name: 圖模型中的Name 在ROS的封裝體系中很是重要,全部的resource(從node到topic到service和 parameter等)都是在某個namespace中用特定的Name進行了定義。 通常來講,resource 能夠在本身的namespace中創 建新的resource,訪問和使用已有的resource。連接能夠創建在不一樣的資源之間,namespace保證了不一樣resource間的Name 不會衝突,也封裝了resource內部。
(能夠參考C++中namespace的概念。由於ROS分佈式系統的設計思路,對與不一樣主機上,不一樣功能區塊,均可以用namespace對其中 的resource name 包括 topic name 等 進行保護,使得name管理更加結構化,更多體如今對於代碼重用性的提升)
Computation graph: Computation graph是一個p2p的網絡結構。Node之間的連接關係的拓撲結構爲 mesh(網狀)
Node:node是一個處理計算的進程。(操做系統中的一個進程,由於要佔用端口號進行通信,多機分佈式系統中還要標明ip,詳見後面的 uri)Node在graph中使用topic service和parameter相互通信,協調工做。在不一樣的系統設計中,node承載的功能粒度也 不同。好比大部分的設備驅動都是單獨佔用一個node,爲了提升代碼複用率常常會有細粒度的劃分,而在不少視覺處理的系統避免使用多節點結構,傳遞圖像 數據會形成系統資源浪費(nodelet的應用)。Node的使用極大的增長了系統模塊化和代碼封裝的程度,也給系統帶來了一些錯誤容忍的能力。
Master node: master node 給ros系統中其餘節點提供命名與註冊的服務。它跟蹤節點中的publisher與 subscriber,service 的server與client,記錄其餘節點的位置(uri標明,host與port),並將這些信息通知給須要 創建連接的節點。(從分佈式系統的角度分析,ros這樣p2p網絡中集中式管理peer信息,也爲仿真環境提供虛擬時鐘 /clock 重要:ROS多機系統中,ros的全局時鐘僅是本機的系統時鐘,多機須要同步系統時間的工具來實現ros內時鐘同步,通常是ntp,pr2應用 linux中的chrony進行基於ntp的系統時間同步)
Message: node之間通信規定的統一數據格式,ros內部有數據格式規定語言來定義,而後由相應語言的client library中的message_generation 組件生成目標代碼。提供統一的串行化/解串行化 方法。
Topic:ros中廣爲使用的是異步的 publish-subscribe 通信模式。這種方式將信息的產生和使用雙方解耦。通常來講,節點沒 有通信對方那邊的信息。Node從須要的topic那取得消息,topic 能夠有多個 subscriber 與publisher。Topic 通常 用於單向,消息流通信。Node 須要同步通信交換信息時通常使用service。Topic 通常擁有很強的類型定義:一種類型的topic只能接受/ 發送特定數據類型(message type)的message。Publisher 沒有被要求類型一致性,可是接受時subscriber會檢查類型 的md5,進而報錯。
Service: service 用於處理ros通信中的同步通信,採用server/client 語義。每一個service type擁 有 request 與 response兩部分,對於service中的 server,ros不會檢查重名(name conflict),只有最後 註冊的server會生效,與client創建鏈接。
Parameter: parameter 能夠看做爲ros系統運行時中定義的全局變量,而master node 中有 parameter server 來維護這些變量。而namespace的存在使得parameter 擁有了很是清晰的層次劃分,避免了重名,並且使 得parameter訪問能夠單獨訪問也能夠樹狀訪問(層層解析namespace)
URI:定位node在分佈式系統中的位置,格式爲: protocol://host:port,protocol通常爲http或者 rosrpc, host爲 hostname 或者 ip 地址,port則爲端口號。
TCPROS:基於tcp協議的ros應用層數據協議,用於解析topic 與 service的二進制數據流。
ROS 通信中,節點經過遠程過程調用來實現創建鏈接,傳輸數據。ROS 中遠程過程調用採用XML-RPC 實現。遠程調用負責管理節點對計算圖 中信息的獲取與更改,還有一些全局的設置。RPC不直接支持數據的流傳輸(經過TCPROS與 UDPROS支持)。XML-RPC 優點在於支持它的語 言類型不少,而XML自己的文本屬性致使方便人調試。XML-RPC被封裝在http協議中傳輸,XML-RPC 調用時無狀態的 (stateless),沒有狀態信息須要追蹤,簡化了控制邏輯。
1》數據類型:
在XML-RPC中,方法參數和其返回值被封裝在value 的實體中,value有如下幾種固定的類型能夠選擇。(xml中體現爲value的子標籤)
string 爲ascii 碼的字符串,爲value的默認格式。不合法的字符只有& 和 <,s & <;表示。
int 或者 i4 是32位的有符號整型,十進制表示中,前綴-號則爲負數。
boolean 只有兩種取值,0和1,用於表示布爾類型。
double 實數類型,前綴-號表示負數。
dataTime.iso8601 日期時間,用iso-8601格式表示。
base64 用 base64算法編碼的二進制字符串。
array values組成的表,在data實體下一層
Struct 又稱爲map 表示關係的集合,每個struct實體是由一個 name 與 value的鍵值對組成。
2》 請求與應答:
遠程過程調用由兩個階段組成:請求(request) 與 應答(response)。 一個調用者將方法調用請求發給 被調用者,而後被調用者返回調用是否成功與相應返回值。
下面將簡述節點與其餘節點如何進行鏈接,最後初始化一個topic data的流傳輸,service 的實現有些許不一樣。
在以前對於節點與計算圖的介紹中,節點在master node處註冊 本身在publish /subscribe topic。經過 registerPublisher()和 registerSubscriber() 。節點在master處註冊完本身的 subscribe/publish topic後,master都會返回一個成功的應答,其中包含全部publisher節點的URI,然 後 subscriber去與相應的publisher創建鏈接傳輸 topic 相關信息(topic name,樹蕨類型,傳輸類型等)。有任何新的 節點去publisher 一個topic而且在master處已經完成本身的註冊時,master會給全部subscribe 這個topic的節點發 出一個publisherUpdate() 請求,裏面包含全部可用的 publisher的URI,topic 消息的數據由TCPROS協議傳輸。
簡單來講就是各個節點在 master處註冊信息,master發現有節點subscribe/publish相同的topic時,將 publisher的 信息經過 RPC 分發給各個subscriber,subscriber與publisher創建第一次鏈接,傳輸topic信 息,而後再根據publisher返回的topic 信息,創建第二次鏈接,publisher開始 傳輸具體的數據。
而對稱的過程是 註銷(unregisteration), publisher 經過遠程調用unregisterPublisher(), 然 後subscriber經過unregisterSubscriber()註銷,然而,是否關閉publisher與 subscriber間的數據流傳 輸取決於節點自己。
Service的工做原理與topic有些許不一樣,同一個service能被多個節點註冊,可是隻有最後一個能被其餘節點接受。一個節點調用 service時,經過lookupService() 遠程調用在master處查找相應service的URI。而後它將經過一個request 消 息調用service的提供者,若是成功了,service提供者將返回一個相應的response 消息,失敗了返回相應錯誤消息,(全部的消息傳輸默 認都是經過 TCPROS協議。)
XML-RPC爲咱們提供了方便整潔的遠程調用協議,可是它的冗長與以文本爲中心的編碼格式使得它不適合高帶寬,低延遲的數據傳輸任務。ROS定義 了本身的二進制數據流傳輸協議,減小了冗餘的協議增長從而增長帶寬,協議設計使得數據幾乎不須要解析(相對於rpc),從而減小延遲。詳細的TCPROS 協議內容能夠在 wiki.ros.org/ROS/TCPROS 找到。
(如今ROS中也有實現的UDPROS協議,能夠經過TransportHints 數據結構指定下層傳輸協議,甚至經過繼承Trasport 類 本身實現本機的進程間通信方法)。
下面撿一些TCPROS中的重點說一下:
Md5:TCPROS爲了保證兩邊傳輸數據類型一致,會在協議頭中給出topic name 的md5 hash算法處理過的值,而每次你生成新的msg 時,md5的值都會由於你內部數據類型的變更而改變,這樣就避免了新msg與 舊msg 傳輸類型不一致的問題。
Subscriber 選項tcp_nodelay :若是是「1」 則給socket 設置 TCP_NODELAY 選項,下降延遲,可能會下降傳輸效率。
Service client 選項:persistent 設置爲1,則service的連接會一直開放給多個 service request
(下面是一些理解: