1. 调用 getifaddrs

The getifaddrs() function first appeared in glibc 2.3, but before glibc 2.3.3, the implementation supported only IPv4 addresses; IPv6 support was added in glibc 2.3.3. Support of address families other than IPv4 is available only on kernels that support netlink.

int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \  
	const int max_count, int *count)  
{  
	struct ifaddrs *ifc;  
	struct ifaddrs *ifc1;  

	*count = 0;
	if (0 != getifaddrs(&ifc))  
	{  
		logError("file: "__FILE__", line: %d, " \  
			"call getifaddrs fail, " \  
			"errno: %d, error info: %s", \  
			__LINE__, errno, STRERROR(errno));  
		return errno != 0 ? errno : EMFILE;  
	}  
	ifc1 = ifc;  
	while (NULL != ifc)  
	{  
		struct sockaddr *s;  
		s = ifc->ifa_addr;  
		if (NULL != s && AF_INET == s->sa_family)  
		{  
			if (max_count <= *count)  
			{  
				logError("file: "__FILE__", line: %d, "\  
				"max_count: %d < iterface count: %d", \  
				__LINE__, max_count, *count);  
				freeifaddrs(ifc1);  
				return ENOSPC;  
			}  
  
			if (inet_ntop(AF_INET, &((struct sockaddr_in *)s)-> \  
			sin_addr, ip_addrs[*count], IP_ADDRESS_SIZE) != NULL)  
			{  
				(*count)++;  
			}  
			else  
			{  
				logWarning("file: "__FILE__", line: %d, " \  
					"call inet_ntop fail, " \  
					"errno: %d, error info: %s", \  
					__LINE__, errno, STRERROR(errno));  
			}  
		}  
  
		ifc = ifc->ifa_next;  
	}  
  
	freeifaddrs(ifc1);  
	return *count > 0 ? 0 : ENOENT;  
}  

2. 调用ioctl

int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \  
	const int max_count, int *count)  
{  
	int s;  
	struct ifconf ifconf;  
	struct ifreq ifr[32];  
	int if_count;  
	int i;  
	int result;  
  
	*count = 0;  
	s = socket(AF_INET, SOCK_STREAM, 0);  
	if (s < 0)  
	{  
		logError("file: "__FILE__", line: %d, " \  
			"socket create fail, errno: %d, error info: %s", \  
			__LINE__, errno, STRERROR(errno));  
		return errno != 0 ? errno : EMFILE;  
	}  
  
	ifconf.ifc_buf = (char *) ifr;  
	ifconf.ifc_len = sizeof(ifr);  
	if (ioctl(s, SIOCGIFCONF, &ifconf) < 0)  
	{  
		result = errno != 0 ? errno : EMFILE;  
		logError("file: "__FILE__", line: %d, " \  
			"call ioctl fail, errno: %d, error info: %s", \  
			__LINE__, result, STRERROR(result));  
 		close(s);  
		return result;  
	}  
  
	if_count = ifconf.ifc_len / sizeof(ifr[0]);  
	if (max_count < if_count)  
	{  
		logError("file: "__FILE__", line: %d, " \  
			"max_count: %d < iterface count: %d", \  
			__LINE__, max_count, if_count);  
 		close(s);  
		return ENOSPC;  
	}  
  
	for (i = 0; i < if_count; i++)  
	{  
		struct sockaddr_in *s_in;  
    		s_in = (struct sockaddr_in *) &ifr[i].ifr_addr;  
    		if (!inet_ntop(AF_INET, &s_in->sin_addr, \  
			ip_addrs[*count], IP_ADDRESS_SIZE))  
		{  
			result = errno != 0 ? errno : EMFILE;  
			logError("file: "__FILE__", line: %d, " \  
				"call inet_ntop fail, " \  
				"errno: %d, error info: %s", \  
				__LINE__, result, STRERROR(result));  
 			close(s);  
			return result;  
    		}  
		(*count)++;  
	}  
  
	close(s);  
	return *count > 0 ? 0 : ENOENT;  
}  

3. 判断一个 ip 是否是本地 ip 的几种方法

  1. 用该 ip 和指定一个端口号,执行b ind 操作,成功则说明是本地 ip,否则不是。
  2. 上一种方法的问题在于,如果指定的端口被占用了,那么及时是本地 ip,bind 也会出错。可以做如下修改:bind 时指定 0 端口,让系统给分配一个可用的端口。
  3. 先用上面提到的获取本地 ip 的两种方法把本地 ip 列表获取到,然后看目标 ip 是否在其中即可。