2012-07-17 31 views
15

Tôi phải có khả năng phát hiện thay đổi địa chỉ IP cho máy khách Mac của mình. Tôi cần phải thực hiện một hành động mỗi lần tôi nhận được một hành động mới, khi tôi đi từ wifi đến có dây ...Cách phát hiện thay đổi địa chỉ IP trên OSX theo lập trình trong C hoặc C++

Bất kỳ ai cũng đã làm điều gì đó tương tự? Tôi hiện đang thăm dò ý kiến ​​mỗi phút và tôi cần phải thay đổi điều đó để có nhiều sự kiện hơn.

+0

trong thời hạn tổng quát hơn, câu hỏi của tôi thực sự là: Trong OS X Cách thực hiện hành động Trong khi thay đổi địa chỉ IP? – reza

+0

Nếu ý định của bạn là phát hiện khi địa chỉ IP mặc định thay đổi để bạn có thể thực hiện một số hành động (ví dụ: gửi địa chỉ mới đến một số máy chủ), bạn đã hoàn tất.Nếu nó là cái gì khác, xin vui lòng cho chúng tôi biết cái gì khác thực sự là, thay vì liên tục đoán ở bước tiếp theo hướng tới những gì bạn muốn thực hiện. (Lý tưởng nhất, bạn nên đặt một câu hỏi mới cho điều đó thay vì thay đổi câu hỏi này, vì nó là viết tắt, đây là một câu hỏi hay, với những gì tôi hy vọng là một câu trả lời khá hay, ngay cả khi đó không phải là câu hỏi của bạn.) – abarnert

Trả lời

22

Có nhiều cách để thực hiện việc này, từ thông báo IOKit bật lên, nhưng đơn giản nhất có lẽ là khung công tác SystemConfiguration.

Bước đầu tiên là để cháy lên scutil và chơi với nó để tìm ra chìa khóa (s) bạn muốn thông báo trên:

$ 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 

Nhìn vào đó, đã nhận nó vào thử đầu tiên. :) Nhưng nếu bạn muốn xem một NIC cụ thể, hoặc sử dụng IPv6 thay vì v4, vv, rõ ràng bạn sẽ muốn có một khóa khác từ danh sách. Lưu ý rằng bạn có thể sử dụng mẫu regex (kiểu POSIX, như được xác định bởi man 3 regex), vì vậy nếu bạn muốn xem, nói bất kỳ NIC nào cho IPv4, bạn có thể sử dụng State:/Network/Interface/.*/IPv4 hoặc nếu bạn muốn nói IPv4 hoặc IPv6 toàn cầu, State:/Network/Global/IPv., v.v.

Bây giờ bạn chỉ cần gọi SCDynamicStoreSetNotificationKeys bằng các phím bạn muốn.

Lưu ý rằng SCDynamicStoreSetNotificationKeys có thể mất mẫu regex (POSIX phong cách, theo định nghĩa của người đàn ông 3 regex)

Kể từ đó là một chút đau đớn trong C, tôi sẽ viết nó bằng 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ác Lý do chính điều này gây đau đớn hơn cho C là bạn cần hàng tá dòng soạn sẵn cho những thứ như tạo một CFArray với CFString trong đó, in các giá trị CFString, quản lý thời gian sống của các đối tượng, v.v ... Từ bình luận của Jeremy Friesner, có C++ sample code nếu bạn muốn đọc 113 dòng C++ hơn 17 dòng Python. Nhưng thực sự, chỉ có một dòng ở đây rằng nên quen thuộc cho những người chưa bao giờ sử dụng Python:

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

... được tương đương với định nghĩa C:

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

Nhưng kỳ lạ, tôi không thể tìm thấy tài liệu tham khảo thực tế hoặc tài liệu hướng dẫn về SystemConfiguration nữa; điều duy nhất xuất hiện cho SCDynamicStoreSetNotificationKeys hoặc các chức năng liên quan nằm trong phần Tường lửa điều hướng của CFNetwork Programming Guide. Nhưng kỹ thuật gốc TN1145: Living in a Dynamic TCP/IP Environment vẫn tồn tại, và nó có đủ nền và mã mẫu để tìm ra cách viết cho chính bạn (và cách phát hiện địa chỉ IP mới khi bạn nhận được thông báo).

Rõ ràng điều này yêu cầu bạn biết chính xác những gì bạn đang cố gắng xem. Nếu bạn không biết điều đó, không ai có thể cho bạn biết cách xem nó. Câu hỏi ban đầu của bạn là cách "phát hiện thay đổi địa chỉ IP".

Mã trên sẽ làm là phát hiện khi địa chỉ mặc định của bạn thay đổi. Đó là địa chỉ được sử dụng khi bạn kết nối một ổ cắm với một địa chỉ internet mà không ràng buộc nó, hoặc kết nối một ổ cắm với '0.0.0.0' để hoạt động như một máy chủ internet. Nếu bạn chưa viết mã máy chủ mà bạn quan tâm, gần như tất cả các máy khách mạng làm việc trước đây, và hầu hết các máy chủ đều làm việc này trừ khi bạn cấu hình chúng theo cách khác, vì vậy đó có thể là tất cả những gì bạn quan tâm.

Bây giờ chúng ta hãy đi qua các ví dụ trong ý kiến ​​của bạn từng người một:

nếu tôi đang cố gắng để xác định một sự thay đổi mạng, wifi với mạng LAN

Không có những điều như thay đổi từ WiFi đến mạng LAN. Khi bạn kết nối với mạng LAN, WiFi vẫn hoạt động. Tất nhiên bạn có thể tự vô hiệu hóa nó trước hoặc sau khi kết nối với mạng LAN, nhưng bạn không phải làm vậy, và đó là một bước riêng biệt, với một thông báo riêng biệt.

Thông thường, việc thêm mạng LAN sẽ thay đổi địa chỉ mặc định của bạn thành địa chỉ mạng LAN, vì vậy /Network/Global sẽ thông báo cho bạn. Nếu hệ điều hành có thể cho biết mạng LAN không thực sự được kết nối với internet hoặc bạn đã thay đổi một số cài đặt ẩn để làm cho nó thích WiFi sang mạng LAN, v.v., nó sẽ không thay đổi địa chỉ mặc định và /Network/Global sẽ không thông báo cho bạn, nhưng có lẽ bạn không quan tâm.

Nếu bạn quan tâm đến việc một giao diện cụ thể có, mất hoặc thay đổi địa chỉ, bạn có thể xem giao diện đó không. Trên hầu hết các máy Mac, Ethernet tích hợp là en0 và Wi-Fi tích hợp là en1, nhưng tất nhiên bạn có thể có đầu nối USB Wi-Fi của bên thứ ba hoặc bạn có thể đang sử dụng điện thoại di động được chia sẻ kết nối hoặc bạn có thể quan tâm không quá nhiều trong địa chỉ IP thực sự của mạng LAN như trong địa chỉ VPN của VPN mà LAN được kết nối, v.v. Nếu bạn đang viết một mục đích đặc biệt, bạn có thể biết giao diện nào bạn quan tâm, để bạn có thể xem, ví dụ: State:/Network/Interface/en0/IPv4. Nếu bạn muốn được thông báo về bất kỳ giao diện nào thay đổi bất kể điều gì, chỉ cần xem State:/Network/Interface/.*/IPv4.

hoặc điểm nóng hoặc wifi khác

Thay đổi từ một mạng WiFi khác (điểm nóng hay cách khác) sẽ thay đổi en1-hoặc, nếu bạn đang sử dụng một adapter WiFi của bên thứ ba, một số khác giao diện. Nếu địa chỉ mặc định của bạn tại thời điểm đến từ WiFi, địa chỉ này cũng sẽ thay đổi Global, có nghĩa là mã ở trên sẽ hoạt động như hiện trạng. Nếu địa chỉ mặc định của bạn vẫn là mạng LAN, Global sẽ không thay đổi, nhưng có thể bạn không quan tâm. Nếu bạn quan tâm, hãy xem Interface/en1 hoặc Interface/.*, v.v., như trên.

những gì tất cả các thiết lập mạng tôi nên xem cho IPV4 và 6

Chỉ cần thay thế IPv4 với IPv6, hoặc sử dụng IPv.. Nhưng bạn có thực sự quan tâm đến IPv6?

gì khác

gì khác làm bạn quan tâm? Nếu có một cái gì đó bạn thực sự muốn thông báo, bạn có lẽ biết cái gì đó là gì. Ngoài ra, nếu hệ thống cho bạn biết địa chỉ foo trên giao diện thanh đã thay đổi thành "ZZ9 Plural Z Alpha" và bạn chưa bao giờ nghe đến giao thức foo, bạn có thể làm gì với thông tin đó một cách hữu ích? Nhưng nếu bạn thực sự muốn nó anyway, một lần nữa, bạn chỉ có thể sử dụng một mẫu regex để xem cho bất cứ điều gì theo từng giao diện.

+0

Concur - Tôi đã 1/2 bằng cách viết một cái gì đó tương tự - mà không có tiếng hét tốt đẹp cho scutil. :) – Joe

+0

Điều này thật tuyệt vời, cảm ơn bạn. Tôi không đọc Python. Điều này đang làm gì? – reza

+3

Có một chương trình ví dụ C/C++ tầm thường-run-run tại http://www.lcscanada.com/jaf/osx_ip_change_notify.cpp (xuất phát từ mã Công nghệ của Apple) ... biên dịch nó bằng "g ++ osx_ip_change_notify.cpp - framework SystemConfiguration -framework Carbon " –

Các vấn đề liên quan