linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)
linux 進程間通信 dbus-glib【實例】詳解一(附代碼)(d-feet工具使用)
linux 進程間通信 dbus-glib【實例】詳解二(上) 消息和消息總線(附代碼)
linux 進程間通信 dbus-glib【實例】詳解二(下) 消息和消息總線(ListActivatableNames和服務器的自動啟動)(附代碼)
linux 進程間通信 dbus-glib【實例】詳解三 數據類型和dteeth(類型簽名type域)(層級結構:服務Service --> Node(對象、object) 等 )(附代碼)
linux 進程間通信 dbus-glib【實例】詳解四(上) C庫 dbus-glib 使用(附代碼)(編寫接口描述文件.xml,dbus-binding-tool工具生成綁定文件)
linux 進程間通信 dbus-glib【實例】詳解四(下) C庫 dbus-glib 使用(附代碼)
文章目錄
- dbus實例講解(二上):消息和消息總線
- 1、D-Bus的消息
- 1.1、消息類型
- 1.2、dbus-send和dbus-monitor
- 2、消息總線(dbus-daemon?)的方法和信號
- 2.1、概述
- 2.2、清單
- 2.3、練習
- 2.3.1、從ListName到d-feet的基本邏輯
dbus實例講解(二上):消息和消息總線
應用程序A和消息總線連接,這個連接獲取了一個眾所周知的公共名(記作連接A)。應用程序A中有對象A1提供了接口I1,接口I1有方法M1。 應用程序B和消息總線連接,要求調用連接A上對象A1的接口I1的方法M1。
在上一講的加法例子中,上面這段話可以實例化為:
應用程序example-service和會話總線連接。這個連接獲取了一個眾所周知的公共名“org.fmddlmyy.Test”。
應用程序example-servic中有對象“/TestObj”提供了接口“org.fmddlmyy.Test.Basic”,接口“org.fmddlmyy.Test.Basic”有方法“Add”。
應用程序d-feet和會話總線連接,要求調用連接“org.fmddlmyy.Test”上對象“/TestObj”的接口“org.fmddlmyy.Test.Basic”的方法“Add”。
應用程序B調用應用程序A的方法,其實就是應用程序B向應用程序A發送了一個類型為“method_call”的消息。 應用程序A通過一個類型為“method_return”的消息將返回值發給應用程序B。我們簡單介紹一下D-Bus總線上的消息。
1、D-Bus的消息
上一講說過最基本的D-Bus協議是一對一的通信協議。與直接使用socket不同,D-Bus是面向消息的協議。 D-Bus的所有功能都是通過在連接上流動的消息完成的。
1.1、消息類型
D-Bus有四種類型的消息:
- method_call 方法調用
- method_return 方法返回
- error 錯誤
- signal 信號
前面介紹的遠程方法調用就用到了method_call和method_return消息。顧名思義,在發生錯誤時會產生error消息。 如果把method_call看作打電話,那么signal消息就是來電了。后面還會詳細討論。
1.2、dbus-send和dbus-monitor
dbus提供了兩個小工具:dbus-send和dbus-monitor。我們可以用dbus-send發送消息。用dbus-monitor監視總線上流動的消息。 讓我們通過dbus-send發送消息來調用前面的Add方法,這時dbus-send充當了應用程序B。用dbus-monitor觀察調用過程中的消息。
啟動example-service:
$ ./example-service在另一個控制臺啟動dbus-monitor:
$ dbus-monitordbus-monitor默認監視會話總線。執行:
$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.fmddlmyy.Test.Basic.Add int32:100 int32:999
輸出為:
method return time=1642572373.469364 sender=:1.124 -> destination=:1.135 serial=118 reply_serial=2int32 1099dbus-monitor的相關輸出包括:
(我的ubuntu輸出)
:1.22就是dbus-send在本次調用中與會話總線所建立連接的唯一名。:1.21是連接“org.fmddlmyy.Test”的唯一名。 在以上輸出中我們可以看到:1.22向“org.fmddlmyy.Test”發送method_call消息,調用Add方法。 :1.21通過method_return消息將調用結果發回:1.22。其它輸出信息會在以后說明。
dbus-send的詳細用法可以參閱手冊。調用遠程方法的一般形式是:
$ dbus-send [--system | --session] --type=method_call --print-reply --dest=連接名 對象路徑 接口名.方法名 參數類型:參數值 參數類型:參數值
dbus-send支持的參數類型包括:string, int32, uint32, double, byte, boolean。
2、消息總線(dbus-daemon?)的方法和信號
2.1、概述
消息總線(dbus-daemon?)是一個特殊的應用,它可以在與它連接的應用之間傳遞消息。 可以把消息總線看作一臺路由器。正是通過消息總線,D-Bus才在一對一的通信協議基礎上實現了多對一和一對多的通信。
消息總線雖然有特殊的轉發功能,但消息總線也還是一個應用。 其它應用與消息總線的通信也是通過1.1節的基本消息類型完成的。作為一個應用,消息總線也提供了自己的接口,包括方法和信號。
我們可以通過向連接“org.freedesktop.DBus ”上對象“/”發送消息來調用消息總線提供的方法。 事實上,應用程序正是通過這些方法連接到消息總線上的其它應用,完成請求公共名等工作的。
2.2、清單
消息總線對象支持第一講中提到的標準接口"org.freedesktop.DBus.Introspectable", 我們可以調用org.freedesktop.DBus.Introspectable.Introspect方法查看消息總線對象支持的接口。例如:
$ dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect
(arm攝像頭上用:[root@RV1126_RV1109:~]# dbus-send --system --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect)
輸出為:
(arm攝像頭)
[root@RV1126_RV1109:~]# dbus-send --system --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect method return time=1642579767.439290 sender=org.freedesktop.DBus -> destination=:1.17 serial=3 reply_serial=2string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node><interface name="org.freedesktop.DBus"><method name="Hello"><arg direction="out" type="s"/></method><method name="RequestName"><arg direction="in" type="s"/><arg direction="in" type="u"/><arg direction="out" type="u"/></method><method name="ReleaseName"><arg direction="in" type="s"/><arg direction="out" type="u"/></method><method name="StartServiceByName"><arg direction="in" type="s"/><arg direction="in" type="u"/><arg direction="out" type="u"/></method><method name="UpdateActivationEnvironment"><arg direction="in" type="a{ss}"/></method><method name="NameHasOwner"><arg direction="in" type="s"/><arg direction="out" type="b"/></method><method name="ListNames"><arg direction="out" type="as"/></method><method name="ListActivatableNames"><arg direction="out" type="as"/></method><method name="AddMatch"><arg direction="in" type="s"/></method><method name="RemoveMatch"><arg direction="in" type="s"/></method><method name="GetNameOwner"><arg direction="in" type="s"/><arg direction="out" type="s"/></method><method name="ListQueuedOwners"><arg direction="in" type="s"/><arg direction="out" type="as"/></method><method name="GetConnectionUnixUser"><arg direction="in" type="s"/><arg direction="out" type="u"/></method><method name="GetConnectionUnixProcessID"><arg direction="in" type="s"/><arg direction="out" type="u"/></method><method name="GetAdtAuditSessionData"><arg direction="in" type="s"/><arg direction="out" type="ay"/></method><method name="GetConnectionSELinuxSecurityContext"><arg direction="in" type="s"/><arg direction="out" type="ay"/></method><method name="ReloadConfig"></method><method name="GetId"><arg direction="out" type="s"/></method><method name="GetConnectionCredentials"><arg direction="in" type="s"/><arg direction="out" type="a{sv}"/></method><property name="Features" type="as" access="read"><annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/></property><property name="Interfaces" type="as" access="read"><annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/></property><signal name="NameOwnerChanged"><arg type="s"/><arg type="s"/><arg type="s"/></signal><signal name="NameLost"><arg type="s"/></signal><signal name="NameAcquired"><arg type="s"/></signal></interface><interface name="org.freedesktop.DBus.Introspectable"><method name="Introspect"><arg direction="out" type="s"/></method></interface><interface name="org.freedesktop.DBus.Peer"><method name="GetMachineId"><arg direction="out" type="s"/></method><method name="Ping"></method></interface><node name="org/freedesktop/DBus"/> </node> " [root@RV1126_RV1109:~]#從輸出可以看到會話總線對象支持標準接口“org.freedesktop.DBus.Introspectable”和接口“org.freedesktop.DBus”。 接口“org.freedesktop.DBus”有16個方法和3個信號。下表列出了“org.freedesktop.DBus”的12個方法的簡要說明:
(這個表日后可能要做搜索用,附個鏈接:http://www.fmddlmyy.cn/mytext.html)
接口“org.freedesktop.DBus”的3個信號是:
2.3、練習
讓我們來試試消息總線提供的方法。
2.3.1、從ListName到d-feet的基本邏輯
用dbus-send調用:
$ dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
(ubuntu里)
輸出為:(略)
(arm攝像頭里)
輸出為:
這是會話總線當前已連接的連接名。在d-feet窗口的左側窗口顯示的就是ListNames返回的連接名。
(ubuntu d-feet軟件)
聰明的讀者也許已經想到使用消息總線的“org.freedesktop.DBus.ListNames”方法和各連接的“org.freedesktop.DBus.Introspectable.Introspect”, 我們就可以像d-feet一樣查看總線上所有連接的所有對象的所有接口的所有方法和信號。
你的想法很好。但有一個問題,我們必須對連接中的對象調用“org.freedesktop.DBus.Introspectable.Introspect”方法。 ListNames只列出了連接名,我們怎么獲取連接中的對象路徑呢?
答案很簡單,如果我們不知道對象路徑就從根目錄開始吧。連接中的對象是按照樹型結構組織的。我們遍歷連接的對象樹就可以找到所有的對象。 調用對象的“org.freedesktop.DBus.Introspectable.Introspect”方法就可以查看對象的所有接口的所有方法和信號。
(如在arm攝像頭里查看"rockchip.netserver"所有方法)
例如:假設我們不知道連接"org.fmddlmyy.Test"里有什么對象,我們可以對根對象"/"執行:
$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test / org.freedesktop.DBus.Introspectable.Introspect
(當然,要先運行作者的example-service服務)
輸出為:
[arnold@ubuntu ~/Arnold_test/20220119_test_dbus_demo4/hello-dbus3-0.1/src]1$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test / org.freedesktop.DBus.Introspectable.Introspect method return time=1642599939.774764 sender=:1.89 -> destination=:1.90 serial=8 reply_serial=2string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node><node name="TestObj"/> </node> " [arnold@ubuntu ~/Arnold_test/20220119_test_dbus_demo4/hello-dbus3-0.1/src]2$“org.fmddlmyy.Test"的對象樹的根節點只有一個子節點"TestObj”,再查看"/TestObj":
$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.freedesktop.DBus.Introspectable.Introspect
[arnold@ubuntu ~/Arnold_test/20220119_test_dbus_demo4/hello-dbus3-0.1/src]2$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.freedesktop.DBus.Introspectable.Introspect method return time=1642601175.664496 sender=:1.89 -> destination=:1.91 serial=9 reply_serial=2string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node><interface name="org.freedesktop.DBus.Introspectable"><method name="Introspect"><arg name="data" direction="out" type="s"/></method></interface><interface name="org.freedesktop.DBus.Properties"><method name="Get"><arg name="interface" direction="in" type="s"/><arg name="propname" direction="in" type="s"/><arg name="value" direction="out" type="v"/></method><method name="Set"><arg name="interface" direction="in" type="s"/><arg name="propname" direction="in" type="s"/><arg name="value" direction="in" type="v"/></method><method name="GetAll"><arg name="interface" direction="in" type="s"/><arg name="props" direction="out" type="a{sv}"/></method></interface><interface name="org.fmddlmyy.Test.Basic"><method name="Add"><arg name="arg0" type="i" direction="in"/><arg name="arg1" type="i" direction="in"/><arg name="ret" type="i" direction="out"/></method></interface> </node> " [arnold@ubuntu ~/Arnold_test/20220119_test_dbus_demo4/hello-dbus3-0.1/src]3$作為一個練習,讓我們來查看系統總線的上的bluez接口。執行:(我發現我沒bluez這個接口😂)
那就在arm攝像頭上看netserver這個接口吧
$ dbus-send --system --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
輸出為:
method return time=1642603380.135709 sender=org.freedesktop.DBus -> destination=:1.22 serial=3 reply_serial=2array [string "org.freedesktop.DBus"string ":1.7"string ":1.8"string "rockchip.netserver"string "org.freedesktop.Avahi"string ":1.22"string ":1.0"string ":1.1"string ":1.2"string ":1.3"string "rockchip.system"string "net.connman"string ":1.4"string "fi.w1.wpa_supplicant1"string "rockchip.dbserver"string ":1.5"string "rockchip.StorageManager"string ":1.6"]我們看到連接"rockchip.netserver"。查看它的根對象:
$ dbus-send --system --type=method_call --print-reply --dest=rockchip.netserver / org.freedesktop.DBus.Introspectable.Introspect
輸出為:
method return time=1642603716.790027 sender=:1.4 -> destination=:1.24 serial=27 reply_serial=2string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node><interface name="org.freedesktop.DBus.Introspectable"><method name="Introspect"><arg name="xml" type="s" direction="out"/></method></interface><interface name="rockchip.netserver.server"><method name="GetService"><arg name="type" type="s" direction="in"/><arg name="json" type="s" direction="out"/></method><method name="GetNetworkIP"><arg name="type" type="s" direction="in"/><arg name="json" type="s" direction="out"/></method><method name="GetConfig"><arg name="service" type="s" direction="in"/><arg name="json" type="s" direction="out"/></method><method name="ScanWifi"></method><signal name="PowerChanged"><arg name="name" type="s"/><arg name="value" type="v"/></signal></interface><node name="net"/> </node>"繼續找下一層net:
dbus-send --system --type=method_call --print-reply --dest=rockchip.netserver /net org.freedesktop.DBus.Introspectable.Introspect
繼續找下一層connman
dbus-send --system --type=method_call --print-reply --dest=rockchip.netserver /net/connman org.freedesktop.DBus.Introspectable.Introspect
繼續:
dbus-send --system --type=method_call --print-reply --dest=rockchip.netserver /net/connman/connmanctl629 org.freedesktop.DBus.Introspectabl e.Introspect
調用接口net.connman.Agent里的Cancel方法:(終于調成功了,發現其他幾個都調不成功,是不是參數沒傳對?)
dbus-send --system --type=method_call --print-reply --dest=rockchip.netserver /net/connman/connmanctl629 net.connman.Agent.Cancel
method return time=1642605903.695343 sender=:1.4 -> destination=:1.29 serial=33 reply_serial=2作者:我們看到了對象"/org/bluez"的所有接口。對象"/org/bluez"還有子節點"service_audio"、“service_input”、“service_network"和"service_serial”。 必要時我們可以接著查下去。d-feet的基本邏輯就是這樣。 后面我們會自己實現一個dteeth。dteeth是命令行程序,可以遍歷指定連接的對象樹,列出所有對象的所有接口的方法和信號。
參考文章:dbus實例講解(二上):消息和消息總線
總結
以上是生活随笔為你收集整理的linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux开机自动启动(自启动)脚本、程
- 下一篇: linux 其他常用命令