当我遇到过这个问题,我的解决办法是安排在网络配置发生了变化,从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