當我遇到過這個問題,我的解決辦法是安排在網絡配置發生了變化,從OS得到通知。當我的程序收到該通知,它會等待幾秒鐘(以希望確保網絡配置完成後改變),然後推倒並重建其所有的插座。這是一個痛苦,但它似乎工作得很好。
當然,沒有操作系統無關的方式(即我所知道的)從OS獲得通知時,網絡配置發生了變化,所以我必須以不同的方式實現它的每個操作系統下。
爲MacOS/X,我生成一個單獨的手錶的網絡系配置線程,這看起來像這樣:
#include <SystemConfiguration/SystemConfiguration.h>
void MyNetworkThreadWatcherFunc(void *)
{
SCDynamicStoreRef storeRef = NULL;
CFRunLoopSourceRef sourceRef = NULL;
if (CreateIPAddressListChangeCallbackSCF(IPConfigChangedCallback, this, &storeRef, &sourceRef) == noErr)
{
CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopDefaultMode);
while(_threadKeepGoing) // may be set to false by main thread at shutdown time
{
CFRunLoopRun();
}
// cleanup time: release our resources
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopDefaultMode);
CFRelease(storeRef);
CFRelease(sourceRef);
}
}
和也有這種設置/支持代碼,從上述函數調用:
static OSStatus MoreSCError(const void *value) {return MoreSCErrorBoolean(value != NULL);}
static OSStatus CFQError(CFTypeRef cf) {return (cf == NULL) ? -1 : noErr;}
static void CFQRelease(CFTypeRef cf) {if (cf != NULL) CFRelease(cf);}
// Create a SCF dynamic store reference and a corresponding CFRunLoop source. If you add the
// run loop source to your run loop then the supplied callback function will be called when local IP
// address list changes.
static OSStatus CreateIPAddressListChangeCallbackSCF(SCDynamicStoreCallBack callback, void *contextPtr, SCDynamicStoreRef *storeRef, CFRunLoopSourceRef *sourceRef)
{
OSStatus err;
SCDynamicStoreContext context = {0, NULL, NULL, NULL, NULL};
SCDynamicStoreRef ref = NULL;
CFStringRef patterns[2] = {NULL, NULL};
CFArrayRef patternList = NULL;
CFRunLoopSourceRef rls = NULL;
// Create a connection to the dynamic store, then create
// a search pattern that finds all entities.
context.info = contextPtr;
ref = SCDynamicStoreCreate(NULL, CFSTR("AddIPAddressListChangeCallbackSCF"), callback, &context);
err = MoreSCError(ref);
if (err == noErr)
{
// This pattern is "State:/Network/Service/[^/]+/IPv4".
patterns[0] = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
err = MoreSCError(patterns[0]);
if (err == noErr)
{
// This pattern is "State:/Network/Service/[^/]+/IPv6".
patterns[1] = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
err = MoreSCError(patterns[1]);
}
}
// Create a pattern list containing just one pattern,
// then tell SCF that we want to watch changes in keys
// that match that pattern list, then create our run loop
// source.
if (err == noErr)
{
patternList = CFArrayCreate(NULL, (const void **) patterns, 2, &kCFTypeArrayCallBacks);
err = CFQError(patternList);
}
if (err == noErr) err = MoreSCErrorBoolean(SCDynamicStoreSetNotificationKeys(ref, NULL, patternList));
if (err == noErr)
{
rls = SCDynamicStoreCreateRunLoopSource(NULL, ref, 0);
err = MoreSCError(rls);
}
// Clean up.
CFQRelease(patterns[0]);
CFQRelease(patterns[1]);
CFQRelease(patternList);
if (err != noErr)
{
CFQRelease(ref);
ref = NULL;
}
*storeRef = ref;
*sourceRef = rls;
return err;
}
static void IPConfigChangedCallback(SCDynamicStoreRef /*store*/, CFArrayRef /*changedKeys*/, void *info)
{
printf("Network config changed! Place code here to send a notification to your main thread, telling him to close and recreate his sockets....\n");
}
而且還有爲使Linux下網絡配置改變的通知(使用插座(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE)))和Windows(使用NotifyAddrChange())當量(也相當晦澀)機制,以我可以發佈,如果他們會有所幫助,但我不想發送垃圾郵件如果你只對MacOS/X解決方案感興趣,這個頁面太多了。
嗨,你可以上傳你的代碼?我非常需要他們在我的應用程序。謝謝 – kuchi 2012-03-18 09:27:25