簡體   English   中英

如何在C或C ++中以編程方式檢測OSX上的IP地址更改

[英]How to detect IP address change on OSX programmatically in C or C++

我必須能夠檢測到我的Mac客戶端的IP地址更改。 我需要在每次換新動作時執行動作,當我從wifi轉到有線時...

有人做過類似的事嗎? 我目前每分鍾都會進行一次調查,我需要將其更改為更多事件驅動。

從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

看看那個,先試試吧。 :)但是如果你想觀看一個特定的網卡,或者使用IPv6而不是v4等,顯然你需要一個不同的密鑰來自列表。 請注意,您可以使用正則表達式模式(POSIX樣式,由man 3 regex定義),因此如果您想要觀看任何用於IPv4的NIC,您可以使用State:/Network/Interface/.*/IPv4 ,或者如果你想說全球IPv4或IPv6, State:/Network/Global/IPv.

現在,您只需使用所需的鍵調用SCDynamicStoreSetNotificationKeys。

請注意,SCDynamicStoreSetNotificationKeys可以采用正則表達式模式(POSIX樣式,由man 3正則表達式定義)

因為它在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 ++如果您寧願閱讀113行C ++而不是17行Python,那么可以使用示例代碼 但實際上,這里只有一行對於從未使用過Python的人來說應該是不熟悉的:

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編程指南”的“導航防火牆”部分中。 但原始技術說明TN1145:生活在動態TCP / IP環境中仍然存在,並且它有足夠的背景和示例代碼來弄清楚如何自己編寫(以及如何在收到通知時檢測新的IP地址)。

顯然,這需要你知道你究竟想要注意什么。 如果你不知道,沒有人能告訴你如何觀察它。 您最初的問題是如何“檢測IP地址更改”。

上面的代碼將檢測您的默認地址何時更改。 這是在將套接字連接到Internet地址而不綁定它時使用的地址,或者將套接字綁定到“0.0.0.0”以充當Internet服務器。 如果您還沒有編寫您關心的服務器代碼,幾乎所有網絡客戶端都會執行前者,大多數服務器會執行后者,除非您另外配置它​​們,因此您可能只關心它們。

現在讓我們逐一查看您的評論中的示例:

如果我正在嘗試確定網絡更改,wifi到LAN

沒有從WiFi變為LAN的事情。 當您連接到LAN時,WiFi仍在工作。 當然,您可以在連接到LAN之前或之后手動禁用它,但是您沒有必要,並且這是一個單獨的步驟,並帶有單獨的通知。

通常,添加LAN會將您的默認地址更改為LAN的地址,因此/Network/Global會通知您。 如果操作系統可以告訴局域網實際上沒有連接到互聯網,或者你已經改變了一些隱藏設置以使其更喜歡WiFi到LAN等,它將不會改變默認地址,並且/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替換IPv4,或使用IPv IPv. 但你真的關心IPv6嗎?

還有什么

你還關心什么? 如果您確實想要通知某些內容,那么您可能知道這是什么。

除此之外,如果系統告訴您條形界面上的foo地址已更改為“ZZ9 Plural Z Alpha”,並且您從未聽說過foo協議,那么您可以對該信息做些什么? 但是如果你真的想要它,那么你可以再次使用正則表達式模式來監視每個界面下的任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM