dbus 모니터 출력을 읽는 방법?


20

우분투 환경에서 dbus가 어떻게 작동하는지 이해하기 위해 dbus-monitor 를 가지고 놀고 있습니다. 이와 관련하여 몇 가지 질문이 있습니다.

  1. 다음을 올바르게 읽는 방법을 알려주시겠습니까? 나는 큰 아이디어를 이해하지만 세부 사항은 이해하지 못합니다.

    signal sender=:1.1948 -> dest=(null destination) serial=1829990 path=/org/ayatana/menu/DA00003; interface=org.ayatana.dbusmenu; member=ItemPropertyUpdated
    int32 23
    string "enabled"
    variant boolean true
    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1399 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications;
    member=GetCapabilities
    

    첫 번째는 신호이고 두 번째는 방법이라는 것을 알았습니다. 목적지 는 신호에 대한 특정 수신기 / 슬롯이있을 수 있음을 의미 합니까 ? 무엇 멤버는 ? 그리고 신호 뒤에 나오는 목록의 항목이 신호에 전달 된 인수입니까? 발신자일련 번호 란 무엇입니까 ?

  2. 볼륨 제어와 알림의 관계에 대해 알아 차 렸습니다. dbus-monitor 출력에서 ​​읽은 내용에서

    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1400 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
    string "gnome-settings-daemon"
    uint32 0
    string "notification-audio-volume-medium"
    string " "
    string ""
    array [
    ]
    array [
    dict entry(
    string "value"
    variant int32 38
    )
    dict entry(
    string "x-canonical-private-synchronous"
    variant string "volume"
    )
    ]
    int32 -1
    

    알림이 메소드에 의해 트리거 된 것 같습니다. 왜 이런 식으로 작동하는지 이해하지 못합니다. 내 생각에, "알림-오디오-볼륨-중간" 방출되는 신호가 있다면 , 통지가이 신호를 듣고 그에 따라 반응 하는 것이 더 의미가있을 것이다. 송신 / 수신이 개인이 아닌 공개 인 경우 더 많은 유연성과 효율성을 허용하지 않습니까? 예를 들어 "알림-오디오-볼륨-중간" 에 대한 공개 신호가있는 경우 그런 다음 여러 응용 프로그램이이 신호를 수신 할 수 있으며 (경쟁 알림 응용 프로그램의 존재를 허용 할 수 있음) 개발자는 신호 전송에 관심을 가져야하지만 신호를 수집하고 처리하는 것은 응용 프로그램의 비즈니스 (또는 기타 해당 신호가 필요한 프로그램).

  3. 저는 Dbus를 처음 접했고 Python에서 Dbus와 함께 일하면서 주로 애플릿을 개발하기 위해 더 많은 것을 배우고 싶습니다. 나는 dbus-python 튜토리얼을 보았고 모든 인터페이스를 듣는 방법 (인터페이스 나 경로 등을 지정하지 않음)을 가르치고 있지만 dbus-monitor처럼 메소드가 호출 될 때 추적하는 방법은 무엇입니까?

그것이 어떻게 작동하는지 가르치는 인내심이 있다면 환영합니다.

답변:


24

D- 버스 소개

  • D-Bus는 서비스 간 통신을위한 수단을 제공 합니다 . 서비스가 될 수 있습니다 익명 및 서비스는 aquire 수 있습니다 (1.6 같은 버스 주소만으로 확인) 잘 알려진 이름 처럼, org.freedesktop.Notifications또는 org.freedesktop.NetworkManager. 로그에서 볼 수있는 발신자와 대상은 서비스입니다. "널 대상"은 브로드 캐스트 : 모든 서비스로의 전송을 의미합니다.

  • 서비스는 하나 이상의 객체 를 버스로 내보낼 수 있습니다 . 객체에는 또는 과 같은 객체 경로 가 제공 됩니다. 객체 경로는 파일 시스템 경로와 같이 슬래시를 구분 기호로 사용합니다./org/freedesktop/NetworkManager/ActiveConnection/1/org/ayatana/menu/DA00003

  • 각 개체는 하나 이상의 인터페이스를 지원할 수 있습니다 . 인터페이스는 공칭 적으로 멤버 (OOP 인터페이스와 매우 유사)로 알려진 일련의 메소드 및 신호에 지나지 않습니다 . 방법과 신호에는 서명이 고정되어 있습니다. 멤버는 항상 잘 알려진 인터페이스 이름으로 네임 스페이스됩니다 .

  • 일단 알려진 이름 은 변경되지 않습니다 .

  • 모든 서비스는 다른 서비스의 신호에 연결하여 비동기 적으로 메소드를 호출 할 수 있습니다. 모든 서비스는 신호를 방출 할 수 있습니다.

신호

지금 당신의 구체적인 질문에.

신호 발신자 = : 1.1948-> 대상 = (널 대상) 시리얼 = 1829990 경로 = / org / ayatana / menu / DA00003; interface = org.ayatana.dbusmenu; member = ItemPropertyUpdated
int32 23
문자열 "사용 가능"
변형 부울 true

예, 맞습니다. 이것은 신호입니다. service :1.1948에 의해 방송되며 "self"객체는 /org/ayatana/menu/DA00003입니다. 신호에는 ItemPropertyUpdated인터페이스에 정의 된 이름 이 있습니다 org.ayatana.dbusmenu( org.ayatana.dbusmenu::ItemPropertyUpdatedC ++ 에서처럼 ). 시리얼은 버스의 이벤트에 대한 일종의 고유 식별자라고 생각합니다.

그런 다음 신호 인수를 봅니다. 인터페이스 documentation 에 따르면 첫 번째 int32 인수는 항목의 id이고 두 번째 문자열은 속성 이름이며 세 번째 변형은 속성 값입니다. 따라서 /org/ayatana/menu/DA00003객체는 항목 ID # 23이 enabled속성을 true로 변경했음을 알려줍니다 .


신호에 대한 또 다른 예 :

신호 발신자 = : 1.1602-> 대상 = (널 대상) 시리얼 = 20408 경로 = / im / pidgin / purple / PurpleObject; interface = im.pidgin.purple.PurpleInterface; member = SendingChatMsg
   int32 47893
   문자열 "test"
   uint32 1
신호 발신자 = : 1.1602-> 대상 = (널 대상) 시리얼 = 20409 경로 = / im / pidgin / purple / PurpleObject; interface = im.pidgin.purple.PurpleInterface; member = IrcSendingText
   int32 64170
   문자열 "PRIVMSG #chat : test

I는 IRC 채널 피진을 사용하여 텍스트 메시지 "테스트"를 송신하고, /im/pidgin/purple/PurpleObject언더 두 신호 출사 im.pidgin.purple.PurpleInterface인터페이스 : 제 일반적인 SendingChatMsg후보다 구체적인를 IrcSendingText.

행동 양식

이제 방법. 메소드는 D-Bus 객체에 무언가를하도록 요청하거나 쿼리 및 리턴 데이터를 수행하는 방법입니다. D-Bus 메서드가 비동기 적으로 호출된다는 점을 제외하면 일반적인 OOP 메서드와 매우 유사합니다.

프로그래밍 방식으로 D-Bus 메서드를 호출 해 봅시다.

import dbus, dbus.proxies

#-- connect to the session bus (as opposed to the system bus)
session = dbus.SessionBus()

#-- create proxy object of D-Bus object
obj_proxy = dbus.proxies.ProxyObject(conn=session,
         bus_name="org.freedesktop.Notifications",     #-- name of the service we are retrieving object from
         object_path="/org/freedesktop/Notifications") #-- the object path

#-- create proxy object of the D-Bus object wrapped into specific interface
intf_proxy = dbus.proxies.Interface(obj_proxy, "org.freedesktop.Notifications")

#-- lastly, create proxy object of the D-Bus method
method_proxy = intf_proxy.get_dbus_method("Notify")

#-- ... and call the method
method_proxy("test from python",
             dbus.UInt32(0),
             "bluetooth",     #-- icon name
             "Notification summary",
             "Here goes notification body",
             [], {},
             5) #-- timeout

인수, 특히 아이콘 이름에 유의하십시오. 귀하의 예 "notification-audio-volume-medium"에는 중간 규모의 볼륨 스피커 아이콘이 있습니다.

맞춤 서비스

자체 D-Bus 서비스를 실행하고, 자체 D-Bus 객체를 내보내고, 고유 한 방법과 신호로 자체 D-Bus 인터페이스를 정의 할 수 있습니다. 전체 개념을 파악하고 dbus모듈 설명서를 읽으면 파이썬에서이 모든 작업을 쉽게 수행 할 수 있습니다 .:)


하루나 이틀 동안 대화를 할 수는 없지만 토론은 환영합니다.
ulidtko

고마워 :) 이것은 많은 것을 명확히합니다. 발신자가 익명이 될 수 있다는 것은 다소 유쾌합니다 .DFeet을 사용할 때 각 발신자에 해당하는 프로세스 이름이 있지만 dbus 모니터 출력에는 반영되지 않습니다. 프로세스를 추적 할 수 있습니까? 이제 파이썬으로 신호를 보내거나 메소드를 제공하거나 상대방의 메소드를 트리거 할 수 있음을 보았습니다. 방법을 가로 챌 수도 있습니까? 프로그램 A가 B의 Dbus 메소드를 트리거하고 무언가를 수행하는지 확인하고 싶다고 가정 해보십시오.
Benjamin

알림 정보 : notify-osd는 능동적으로 신호를 찾는 것이 아니라 다른 응용 프로그램에 의해 수동적으로 트리거됩니다. 그것이 비현실적이지 않습니까, 아니면 Dbus에 대해 오해하지 않습니까? notify-osd를 대체하고 일종의받은 편지함에서 알림을 수집하는 응용 프로그램을 만들고 싶습니다. 신호를 들으면서 알림을 가로 챌 수 있습니까?
Benjamin

@Benjamin, 해외 서비스로 향하는 메소드 호출을 가로 채고 싶을 때 디자인이 깨 졌다고 생각할 수 있습니다. 당신이-OSD를 통지 대체하기 위해 무엇을해야 프로그램을 작성하는 것입니다 제공org.freedesktop.Notifications 서비스를. 이렇게하면이 서비스에 대한 모든 메소드 호출이 코드에서 처리됩니다.
ulidtko

"자기"obejct는 무엇입니까?
kawing-chiu 1

10

또한 파이썬 스크립트로 dbus를 통해 데스크탑 알림을 수집하는 솔루션을 찾고있었습니다. 이 질문은 인터넷 검색에서 가장 가까운 질문이지만 notify-osd에 대한 대체품을 작성하는 것은 지나친 것처럼 보입니다. :)

최근 알림 애플릿 소스를 살펴보면 dbus 메시지를 모니터링하는 방법에 대한 힌트를 얻었으며 다음은 파이썬 구현입니다.

import gtk
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def filter_cb(bus, message):
    # the NameAcquired message comes through before match string gets applied
    if message.get_member() != "Notify":
        return
    args = message.get_args_list()
    # args are
    # (app_name, notification_id, icon, summary, body, actions, hints, timeout)
    print("Notification from app '%s'" % args[0])
    print("Summary: %s" % args[3])
    print("Body: %s", args[4])


DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
bus.add_match_string(
    "type='method_call',interface='org.freedesktop.Notifications',member='Notify'")
bus.add_message_filter(filter_cb)
gtk.main()

dbus 메시지 모니터링과 관련된 간단한 파이썬 예제가 많지 않기 때문에 누군가에게 도움이되기를 바랍니다.


1
그것은 확실히 나를 도왔다! 대단히 감사합니다! 알림 에는 메서드 호출 사용 되므로 "type = 'method_call'"은 필요하지 않습니다 . 사양에 신호가 없습니다. 또한 "member = 'Notify'"도 필요하지 않습니다. 이미 함수에서 필터링 했으므로 (첫 번째 NameAquired메시지 로 인해이를 피할 수 없습니다 )
MestreLion
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.