17

Mac クライアントの IP アドレスの変更を検出できなければなりません。Wi-Fi から有線に切り替えると、新しいものを取得するたびにアクションを実行する必要があります...

誰かが似たようなことをしましたか?私は現在毎分ポーリングを行っており、よりイベント駆動型になるように変更する必要があります。

4

1 に答える 1

30

これを行うには、IOKit 通知から複数の方法がありますが、最も簡単なのはおそらく SystemConfiguration フレームワークです。

最初のステップは、scutil を起動して操作し、通知が必要なキーを特定することです。

$ scutil
> list
...
> n.add State:/Network/Global/IPv4
> n.watch
... unplug your network cable (or disconnect from WiFi)
notification callback (store address = 0x10e80e3c0).
changed key [0] = State:/Network/Global/IPv4

それを見て、最初の試みでそれを手に入れました。:) しかし、特定の NIC を監視したい場合、または v4 の代わりに IPv6 を使用したい場合などは、リストとは異なるキーが必要になることは明らかです。正規表現パターン (で定義されている POSIX スタイル) を使用できることに注意してくださいman 3 regex。したがって、たとえば IPv4 の任意の NIC を監視したい場合は、 を使用できますState:/Network/Interface/.*/IPv4。また、グローバルな IPv4 または IPv6State:/Network/Global/IPv.などを使用したい場合は、

これで、必要なキーを指定して SCDynamicStoreSetNotificationKeys を呼び出すだけです。

SCDynamicStoreSetNotificationKeys は正規表現パターン (man 3 regex で定義されている POSIX スタイル) を使用できることに注意してください。

C では少し面倒なので、Python で記述します。

#!/usr/bin/python

from Foundation import *
from SystemConfiguration import *

def callback(store, keys, info):
  for key in keys:
    print key, SCDynamicStoreCopyValue(store, key)

store = SCDynamicStoreCreate(None, 
                             "global-network-watcher",
                             callback,
                             None)
SCDynamicStoreSetNotificationKeys(store,
                                  None,
                                  ['State:/Network/Global/IPv4'])
CFRunLoopAddSource(CFRunLoopGetCurrent(),
                   SCDynamicStoreCreateRunLoopSource(None, store, 0),
                   kCFRunLoopCommonModes)
CFRunLoopRun()

これが C でより苦痛である主な理由は、CFString を含む CFArray の作成、CFString 値の出力、オブジェクトの有効期間の管理などのために、数十行のボイラープレートが必要になることです。Jeremy Friesner のコメントから、C++があります。 17 行の Python よりも 113 行の C++ を読みたい場合は、サンプル コードを利用できます。しかし、実際には、Python を使用したことがない人にはなじみのないはずの行が 1 つだけあります。

def callback(store, keys, info):
  for key in keys:
    print key, SCDynamicStoreCopyValue(store, key)

… C の定義と同等です。

void callback(SCDynamicStoreRef store, CFArrayRef keys, void *info) {
  /* iterate over keys, printing something for each one */
}

奇妙なことに、SystemConfiguration に関する実際のリファレンスやガイド ドキュメントが見つかりません。SCDynamicStoreSetNotificationKeys または関連する関数について出てくる唯一のものは、CFNetwork Programming Guideの Navigating Firewalls セクションにあります。しかし、元の技術情報 TN1145: Living in a Dynamic TCP/IP Environmentはまだ存在しており、これを自分で記述する方法 (および通知を受けたときに新しい IP アドレスを検出する方法) を理解するのに十分な背景とサンプル コードがあります。

明らかに、これには、何を監視しようとしているのかを正確に知る必要があります。あなたがそれを知らなければ、それを監視する方法を誰も教えてくれません。最初の質問は、「IP アドレスの変更を検出する」方法でした。

上記のコードが行うことは、デフォルトのアドレスがいつ変更されたかを検出することです。これは、ソケットをインターネット アドレスにバインドせずに接続する場合、またはソケットを「0.0.0.0」にバインドしてインターネット サーバーとして機能させる場合に使用されるアドレスです。関心のあるサーバー コードを作成していない場合、ほとんどすべてのネットワーク クライアントは前者を実行し、ほとんどのサーバーは別の方法で構成しない限り後者を実行します。

それでは、コメントの例を 1 つずつ見ていきましょう。

ネットワークの変更を確認しようとしている場合、wifi から LAN

WiFiからLANに変えるなんてことはありません。LAN に接続すると、WiFi は引き続き機能します。もちろん、LAN に接続する前または後に手動で無効にすることもできますが、その必要はありません。これは別の手順であり、別の通知があります。

通常、LAN を追加すると、デフォルトのアドレスが LAN のアドレスに変更されるため、/Network/Global通知されます。OS が LAN が実際にはインターネットに接続されていないことを認識できる場合、または非表示の設定を変更して LAN よりも WiFi を優先するようにした場合などは、デフォルトのアドレスは変更され/Network/Globalず、通知もされませんが、あなたはおそらく気にしません。

特定のインターフェースがアドレスを取得、喪失、または変更するかどうかに関心がある場合は、そのインターフェースを監視できます。ほとんどの Mac では、組み込みのイーサネットは en0、組み込みの WiFi は en1 ですが、もちろん、サードパーティ製の USB WiFi コネクタを使用している場合や、テザー付きの携帯電話を使用している場合や、興味がある場合があります。 LAN の実際の IP アドレスではなく、LAN が接続されている VPN の VPN アドレスなどです。特別な目的で何かを書いている場合は、関心のあるインターフェイスをおそらく知っているので、見ることができます。例: State:/Network/Interface/en0/IPv4。インターフェイスが変更されたときに通知を受け取りたい場合は、 を見てState:/Network/Interface/.*/IPv4ください。

またはホットスポットまたは別のwifiへ

ある WiFi ネットワークから別のネットワーク (ホットスポットまたはそれ以外) に変更すると、en1 が変更されます。または、サードパーティの WiFi アダプターを使用している場合は、他のインターフェイスが変更されます。その時点でのデフォルト アドレスが WiFi からのものである場合は、それも変更さGlobalれます。つまり、上記のコードはそのまま機能します。デフォルトのアドレスが依然として LAN である場合、Global変更はありませんが、おそらく気にする必要はありません。お手入れをする場合は、上記のように時計Interface/en1Interface/.*などをしてください。

IPV4 および 6 で監視すべきすべてのネットワーク設定

IPv4 を IPv6 に置き換えるか、IPv.. しかし、あなたは本当にIPv6を気にしますか?

ほかに何か

他に何を気にしますか?実際に通知が必要なものがある場合、おそらくそれが何であるかを知っているでしょう。

さらに、bar インターフェイスの foo アドレスが「ZZ9 Plural Z Alpha」に変更され、foo プロトコルについて聞いたことがないとシステムから通知された場合、その情報を使って何ができるでしょうか? しかし、とにかくそれが本当に必要な場合は、正規表現パターンを使用して、各インターフェイスの下にあるものを監視できます。

于 2012-07-17T23:53:34.463 に答える