使用 NetworkManager 和 Python 断开 WiFi 接入点

发布于 2024-12-28 04:10:35 字数 4221 浏览 0 评论 0原文

我正在构建一个Python应用程序,它必须在linux机器上连接和断开Wifi。我正在使用 NetworkManager 层,通过 cnetworkmanager 中找到的很好的网络管理器库(NetworkManager 的 python CLI http:// /vidner.net/martin/software/cnetworkmanager/ 感谢 Martin Vidner),在守护进程(名为 stationd)中。 该守护进程运行 gobject.MainLoop。一旦 timeout_add_seconds 唤醒(由 GUI 中用户的操作触发),我必须断开当前正在运行的 Wifi 并连接到新的 Wifi:

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)

from networkmanager import NetworkManager
import networkmanager.applet.settings as settings
from networkmanager.applet import USER_SERVICE 
from networkmanager.applet.service import NetworkManagerUserSettings, NetworkManagerSettings
import time
import memcache

import gobject
loop = gobject.MainLoop()

nm = NetworkManager()

dummy_handler = lambda *args: None

cache = memcache.Client(['127.0.0.1:11211',] )


def get_device(dev_spec, hint):
    candidates = []
    devs = NetworkManager().GetDevices()
    for dev in devs:
        if dev._settings_type() == hint:
            candidates.append(dev)
    if len(candidates) == 1:
        return candidates[0]
    for dev in devs:
        if dev["Interface"] == dev_spec:
            return dev
    print "Device '%s' not found" % dev_spec
    return None

def kill_allconnections():
    connections=nm['ActiveConnections']
    for c in connections:
        print c.object_path
        nm.DeactivateConnection(c.object_path)

class Wifi(object):

    def connect(self, ssid, security="open", password=None):
        "Connects to given Wifi network"
        c=None # connection settings
        us = NetworkManagerUserSettings([])
        if security=="open":
            c = settings.WiFi(ssid)
        elif security=="wep":
            c = settings.Wep(ssid, password)
        elif security=="wpa":
            c = settings.WpaPsk(ssid, password)
        else:
            raise AttributeError("invalid security model '%s'"%security)
        svc = USER_SERVICE
        svc_conn = us.addCon(c.conmap)
        hint = svc_conn.settings["connection"]["type"]
        dev = get_device("", hint)
        appath = "/"
        nm.ActivateConnection(svc, svc_conn, dev, appath, reply_handler=dummy_handler, error_handler=dummy_handler)


def change_network_settings():
    key="station:network:change"
    change=cache.get(key)
    if change is not None:
        print "DISCONNECT"
        kill_allconnections()
        print "CHANGE SETTINGS"
        wifi=cache.get(key+':wifi')
        if wifi is not None:
            ssid=cache.get(key+':wifi:ssid')
            security=cache.get(key+':wifi:security')
            password=cache.get(key+':wifi:password')
            print "SWITCHING TO %s"%ssid
            Wifi().connect(ssid, security, password)
        cache.delete(key)
    return True    

def mainloop():
   gobject.timeout_add_seconds(1, change_network_settings)
   try:
      loop.run()
   except KeyboardInterrupt:
      loop.quit()

if __name__=="__main__":
    mainloop()

这对于第一个连接来说运行完美(阅读:盒子未连接,守护进程运行并且盒子完美连接到 Wifi)。问题是当我尝试连接到另一个 Wifi 时:kill_allconnections() 默默运行,并且 connect 方法在 nm.ActivateConnection 上引发异常:

Traceback (most recent call last):
  File "stationd.py", line 40, in change_network_settings
    Wifi().connect(ssid, security, password)
  File "/home/biopredictive/station/lib/network.py", line 88, in connect
    us = NetworkManagerUserSettings([])
  File "/home/biopredictive/station/lib/networkmanager/applet/service/__init__.py", line 71, in __init__
    super(NetworkManagerUserSettings, self).__init__(conmaps, USER_SERVICE)
  File "/home/biopredictive/station/lib/networkmanager/applet/service/__init__.py", line 33, in __init__
    dbus.service.Object.__init__(self, bus, opath, bus_name)
  File "/usr/lib/pymodules/python2.6/dbus/service.py", line 480, in __init__
    self.add_to_connection(conn, object_path)
  File "/usr/lib/pymodules/python2.6/dbus/service.py", line 571, in add_to_connection
    self._fallback)
KeyError: "Can't register the object-path handler for '/org/freedesktop/NetworkManagerSettings': there is already a handler"

看起来我以前的连接没有释放其所有资源? 我对 gobject/dbus 编程非常陌生。你能帮忙吗?

I’m building an Python application that has to connect and disconnect from Wifi on linux box. I’m using NetworkManager layer, through the nice networkmanager lib found in cnetworkmanager (a python CLI for NetworkManager http://vidner.net/martin/software/cnetworkmanager/ thanx to Martin Vidner), in a daemon (named stationd).
This daemon runs a gobject.MainLoop. Once a timeout_add_seconds awake (triggers by a action of user in GUI), I have to disconnect current running Wifi and connect to a new one:

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)

from networkmanager import NetworkManager
import networkmanager.applet.settings as settings
from networkmanager.applet import USER_SERVICE 
from networkmanager.applet.service import NetworkManagerUserSettings, NetworkManagerSettings
import time
import memcache

import gobject
loop = gobject.MainLoop()

nm = NetworkManager()

dummy_handler = lambda *args: None

cache = memcache.Client(['127.0.0.1:11211',] )


def get_device(dev_spec, hint):
    candidates = []
    devs = NetworkManager().GetDevices()
    for dev in devs:
        if dev._settings_type() == hint:
            candidates.append(dev)
    if len(candidates) == 1:
        return candidates[0]
    for dev in devs:
        if dev["Interface"] == dev_spec:
            return dev
    print "Device '%s' not found" % dev_spec
    return None

def kill_allconnections():
    connections=nm['ActiveConnections']
    for c in connections:
        print c.object_path
        nm.DeactivateConnection(c.object_path)

class Wifi(object):

    def connect(self, ssid, security="open", password=None):
        "Connects to given Wifi network"
        c=None # connection settings
        us = NetworkManagerUserSettings([])
        if security=="open":
            c = settings.WiFi(ssid)
        elif security=="wep":
            c = settings.Wep(ssid, password)
        elif security=="wpa":
            c = settings.WpaPsk(ssid, password)
        else:
            raise AttributeError("invalid security model '%s'"%security)
        svc = USER_SERVICE
        svc_conn = us.addCon(c.conmap)
        hint = svc_conn.settings["connection"]["type"]
        dev = get_device("", hint)
        appath = "/"
        nm.ActivateConnection(svc, svc_conn, dev, appath, reply_handler=dummy_handler, error_handler=dummy_handler)


def change_network_settings():
    key="station:network:change"
    change=cache.get(key)
    if change is not None:
        print "DISCONNECT"
        kill_allconnections()
        print "CHANGE SETTINGS"
        wifi=cache.get(key+':wifi')
        if wifi is not None:
            ssid=cache.get(key+':wifi:ssid')
            security=cache.get(key+':wifi:security')
            password=cache.get(key+':wifi:password')
            print "SWITCHING TO %s"%ssid
            Wifi().connect(ssid, security, password)
        cache.delete(key)
    return True    

def mainloop():
   gobject.timeout_add_seconds(1, change_network_settings)
   try:
      loop.run()
   except KeyboardInterrupt:
      loop.quit()

if __name__=="__main__":
    mainloop()

This runs perfectly for a first connection (read : the box is not connected, daemon is ran and box connects flawlessly to Wifi). Issue is when I try to connect to another Wifi : kill_allconnections() is ran silently, and connect method raises an exception on nm.ActivateConnection:

Traceback (most recent call last):
  File "stationd.py", line 40, in change_network_settings
    Wifi().connect(ssid, security, password)
  File "/home/biopredictive/station/lib/network.py", line 88, in connect
    us = NetworkManagerUserSettings([])
  File "/home/biopredictive/station/lib/networkmanager/applet/service/__init__.py", line 71, in __init__
    super(NetworkManagerUserSettings, self).__init__(conmaps, USER_SERVICE)
  File "/home/biopredictive/station/lib/networkmanager/applet/service/__init__.py", line 33, in __init__
    dbus.service.Object.__init__(self, bus, opath, bus_name)
  File "/usr/lib/pymodules/python2.6/dbus/service.py", line 480, in __init__
    self.add_to_connection(conn, object_path)
  File "/usr/lib/pymodules/python2.6/dbus/service.py", line 571, in add_to_connection
    self._fallback)
KeyError: "Can't register the object-path handler for '/org/freedesktop/NetworkManagerSettings': there is already a handler"

It looks like my former connection didn’t release all its resources ?
I’m very new to gobject/dbus programming. Would you please help ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青衫负雪 2025-01-04 04:10:35

我在 D-Bus 邮件列表上回复了。在这里引用存档:

class Wifi(...):
    def connect(...):
        ...
        us = NetworkManagerUserSettings([]) 

NetworkManagerUserSettings 是服务器,而不是客户端。 (这是一个设计
NM 的怪癖已在 NM 0.9 中消除)
您应该只为守护进程创建一个,而不是为每个连接创建一个
试图。

I have answered on the D-Bus mailing list. Quoting here for the archive:

class Wifi(...):
    def connect(...):
        ...
        us = NetworkManagerUserSettings([]) 

NetworkManagerUserSettings is a server, not a client. (It's a design
quirk of NM which was eliminated in NM 0.9)
You should create only one for the daemon, not for each conection
attempt.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文