4

我正在尝试确定我的 Macbook 所在的网段,因为然后我想使用 CFHost 类扫描该网段以查找活动主机(基本 IP 扫描仪)。因此,我需要活动接口的 IP 和网络掩码。这就是我获得IP的方式:

NSString *ipAddr = [[[NSHost currentHost] addresses] objectAtIndex:0];

但我完全不知道如何获得网络掩码,所以我有点卡住了。特别是因为我在 Objective-C 方面还很新,而且我对纯 C 的知识也不是很广。我查看了 CFHost、CFNetwork、NSHost 和各种 Google 搜索结果,但到目前为止还没有发现任何有用的东西。

作为最后的手段,我想我可以进行某种系统调用,或者从文件中读取它(哪个?),但如果可能的话,我想避免这种情况。

那么,如何获取与通过 NSHost 获取的 ip 匹配的网络掩码呢?任何建议将不胜感激。

谢谢!

4

3 回答 3

12

所以,总结一下,我终于开始研究系统配置 API。与往常一样,一旦你知道这并不难。

@0xced - 感谢您为我指明正确的方向。我会赞成您的回答,但我没有足够的声誉这样做。

这是我的解决方案,适用于任何好奇或处于相同情况的人。它涉及挖掘动态存储。有关API 的信息,请参阅此内容。您可以使用 scutil 命令行实用程序查看动态存储所保存的信息(请参阅 x-man-page://8/scutil )。

这是我的步骤。首先,您需要一个会话:

SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);

然后,我尝试获取主接口(例如 en1):

CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Global/IPv4"));
NSString *primaryInterface = [(__bridge NSDictionary *)global valueForKey:@"PrimaryInterface"];

最后,我构建了一个包含接口的字符串,以便能够查询正确的键。当然,它应该类似于 State:/Network/Interface/en1/IPv4,具体取决于接口。这样我就可以得到一个带有 ip 和网络掩码的数组。在我的 Macbook 上,这些数组分别只保存一个 ip 和一个网络掩码。我想其他 Mac 可能会有所不同,我将不得不验证这一点。对于我的测试,我只取了数组中的第一个(也是唯一一个)元素,但是必须在那里实现某种大小检查。

NSString *interfaceState = [NSString stringWithFormat:@"State:/Network/Interface/%@/IPv4", primaryInterface];

CFPropertyListRef ipv4 = SCDynamicStoreCopyValue (storeRef, (CFStringRef)interfaceState);
CFRelease(storeRef);

NSString *ip = [(__bridge NSDictionary *)ipv4 valueForKey:@"Addresses"][0];
NSString *netmask = [(__bridge NSDictionary *)ipv4 valueForKey:@"SubnetMasks"][0];
CFRelease(ipv4);

这只是为了测试,所以边缘有点粗糙。您将不得不寻找保留计数等。它只是为了了解如何完成而编写的。

于 2011-08-10T21:58:43.840 回答
3

马丁给出了一个很好的答案。
他在 ARC 版本中的代码在这里:

+ (NSDictionary *)primaryIPv4AddressInfoFromSystemConfiguration
{
    SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);
    if (!storeRef)
    {
        return nil;
    }

    NSDictionary *IPv4Dictionary = nil;
    CFPropertyListRef global = SCDynamicStoreCopyValue(storeRef, CFSTR("State:/Network/Global/IPv4"));
    id primaryInterface = [(NSDictionary *)CFBridgingRelease(global) valueForKey:@"PrimaryInterface"];
    if (primaryInterface)
    {
        NSString *interfaceState = @"State:/Network/Interface/";
        interfaceState = [[interfaceState stringByAppendingString:(NSString *)primaryInterface] stringByAppendingString:@"/IPv4"];
        CFPropertyListRef IPv4PropertyList = SCDynamicStoreCopyValue(storeRef, (__bridge CFStringRef)interfaceState);
        IPv4Dictionary = (NSDictionary *)CFBridgingRelease(IPv4PropertyList);
    }

    CFRelease(storeRef);
    return IPv4Dictionary;
}

+ (NSDictionary *)primaryIPv6AddressInfoFromSystemConfiguration
{
    SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);
    if (!storeRef)
    {
        return nil;
    }

    NSDictionary *IPv6Dictionary = nil;
    CFPropertyListRef global = SCDynamicStoreCopyValue(storeRef, CFSTR("State:/Network/Global/IPv6"));
    id primaryInterface = [(NSDictionary *)CFBridgingRelease(global) valueForKey:@"PrimaryInterface"];
    if (primaryInterface)
    {
        NSString *interfaceState = @"State:/Network/Interface/";
        interfaceState = [[interfaceState stringByAppendingString:(NSString *)primaryInterface] stringByAppendingString:@"/IPv6"];
        CFPropertyListRef IPv6PropertyList = SCDynamicStoreCopyValue(storeRef, (__bridge CFStringRef)interfaceState);
        IPv6Dictionary = (NSDictionary *)CFBridgingRelease(IPv6PropertyList);
    }

    CFRelease(storeRef);
    return IPv6Dictionary;
}
于 2015-07-07T16:26:30.383 回答
2

您将不得不使用系统配置 API。请参阅系统配置编程指南系统配置框架参考

于 2011-07-30T20:05:57.760 回答