写在开头
最近一次tcp连接设备,设备输入流处理及控制设备操作的项目中,用到了通过连接wifi局域网通信,当时用的是wifi的网关地址作为设备的ip。查阅资料的时候,发现网上的回复都是一样的版本,笔者亲试此版本在APP允许无线局域网和蜂窝数据都打开的情况下,有很大的几率会拿到蜂窝移动数据的ip。很是头疼,产品自然是不会接受APP打开的时候只选择使用无线局域网情况下的正常运行。几经周折,最后解决了这个问题,在这篇文章上记录一下。有相同情况的可以来讨论一下。
有风险代码的版本
** 获取网关 **
+ (NSString *)getGatewayIpForCurrentWiFi{
NSString *address = @"error";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0) {
// Loop through linked list of interfaces
temp_addr = interfaces;
//*/
while(temp_addr != NULL) {
/*/
int i=255;
while((i--)>0)
//*/
if(temp_addr->ifa_addr->sa_family == AF_INET) {
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]){
// Get NSString from C String //ifa_addr
//ifa->ifa_dstaddr is the broadcast address, which explains the "255's"
// address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)];
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
//routerIP----192.168.1.255 广播地址
NSLog(@"broadcast address--%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]);
//--192.168.1.106 本机地址
NSLog(@"local device ip--%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]);
//--255.255.255.0 子网掩码地址
NSLog(@"netmask--%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)]);
//--en0 端口地址
NSLog(@"interface--%@",[NSString stringWithUTF8String:temp_addr->ifa_name]);
in_addr_t i = inet_addr([address cStringUsingEncoding:NSUTF8StringEncoding]);
in_addr_t* x = &i;
unsigned char *s = getdefaultgateway(x);
NSString *ip=[NSString stringWithFormat:@"%d.%d.%d.%d",s[0],s[1],s[2],s[3]];
free(s);
return ip;
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
return @"0.0.0.0";
}
复制代码
其中getdefaultgateway在c文件getgateway.c的代码如下:
unsigned char * getdefaultgateway(in_addr_t * addr)
{
unsigned char * octet=malloc(4);
#if 0
/* net.route.0.inet.dump.0.0 ? */
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_DUMP, 0, 0/*tableid*/};
#endif
/* net.route.0.inet.flags.gateway */
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return octet;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
return octet;
}
for(p=buf; prtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
for (int i=0; i<4; i++){
octet[i] = ( ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr >> (i*8) ) & 0xFF;
}
}
}
free(buf);
}
return octet;
}
复制代码
完美精简解决的版本
+ (NSString *)getGatewayIP {
NSString *ipString = nil;
struct in_addr gatewayaddr;
int r = getdefaultgateway(&(gatewayaddr.s_addr));
if(r >= 0) {
ipString = [NSString stringWithFormat: @"%s",inet_ntoa(gatewayaddr)];
} else {
NSLog(@"Wifi is not connected or you are using simulator Gateway ip address will be nil");
}
return ipString;
}
复制代码
其中getdefaultgateway在c文件getgateway.c的代码一样。