Ответ 1
Существует несколько способов сделать это, начиная с уведомлений 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, вы можете использовать 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, заключается в том, что вам нужны десятки строк шаблона для таких вещей, как создание CFArray с CFString в нем, печать значений CFString, управление временем жизни объектов и т.д. Из комментария Джереми Фризнера, там код кода С++ доступен, если вы предпочитаете читать 113 строк С++, чем 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-адреса".
Что будет делать код выше, это определить, когда изменяется адрес по умолчанию. Это адрес, который используется при подключении сокета к интернет-адресу без привязки к нему или привязка сокета к "0.0.0.0" для работы в качестве интернет-сервера. Если вы не написали код сервера, о котором вы заботитесь, почти все сетевые клиенты делают первый, и большинство серверов делают последнее, если вы не настроили их иначе, так что, возможно, все, о чем вы заботитесь.
Теперь давайте рассмотрим примеры в ваших комментариях один за другим:
если я пытаюсь определить изменение сети, wifi to LAN
Нет такой вещи, как переход от WiFi к локальной сети. Когда вы подключаетесь к локальной сети, WiFi все еще работает. Конечно, вы можете вручную отключить его до или после подключения к локальной сети, но вам не обязательно, и это отдельный шаг с отдельным уведомлением.
Обычно добавление локальной сети изменяет ваш адрес по умолчанию на адрес LAN, поэтому /Network/Global
уведомит вас. Если ОС может сказать, что ЛВС фактически не подключена к Интернету, или вы изменили некоторые скрытые настройки, чтобы заставить ее использовать WiFi в локальной сети и т.д., Он не изменит адрес по умолчанию, а /Network/Global
не будет уведомлять вы, но вам, вероятно, все равно.
Если вы заботитесь о том, получает ли конкретный интерфейс, проигрывает или меняет адрес, вы можете посмотреть этот интерфейс. На большинстве компьютеров Mac встроенный Ethernet - en0, а встроенный Wi-Fi - en1, но, конечно же, у вас может быть USB-разъем стороннего производителя, или вы можете использовать сотовый телефон, или вы можете быть заинтересованы не столько в фактическом IP-адресе ЛВС, сколько в VPN-адресе VPN, к которому подключена ЛВС и т.д. Если вы пишете что-то особую цель, вы, вероятно, знаете, какой интерфейс вам интересен, поэтому вы можете смотреть, например, State:/Network/Interface/en0/IPv4
. Если вы хотите, чтобы вас уведомили об изменении любого интерфейса, просто посмотрите State:/Network/Interface/.*/IPv4
.
или в горячую точку или другую wifi
Переход из одной сети WiFi в другую (точка доступа или иначе) изменит значение en1 или, если вы используете сторонний WiFi-адаптер, другой интерфейс. Если ваш адрес по умолчанию в данный момент поступает из WiFi, он также изменит Global
, что означает, что приведенный выше код будет работать как есть. Если ваш адрес по умолчанию по-прежнему является вашей локальной сетью, Global
не изменится, но вам, вероятно, все равно. Если вам все равно, смотрите Interface/en1
или Interface/.*
и т.д., Как указано выше.
какие все сетевые настройки я должен смотреть для IPV4 и 6
Просто замените IPv4 на IPv6 или используйте IPv.
. Но вы действительно волнуете IPv6?
что еще
Что еще вам нужно? Если есть что-то, о чем вы действительно хотите получить уведомление, вы, вероятно, знаете, что это такое.
Кроме того, если система сообщает вам, что адрес foo на интерфейсе панели был изменен на "ZZ9 Plural Z Alpha", и вы никогда не слышали о протоколе foo, что вы могли бы с пользой сделать с этой информацией? Но если вы действительно этого хотите, опять же, вы можете просто использовать шаблон регулярных выражений, чтобы следить за чем-либо под каждым интерфейсом.