在Linux下开发网络程序时,经常会遇到需要取本地网络接口名、IP、广播地址、子网掩码或者MAC地址等信息的需求,最常见的办法是配合宏SIOCGIFHWADDR、SIOCGIFADDR、SIOCGIFBRDADDR与SIOCGIFNETMASK作为参数调用函数ioctl分别获得MAC地址、IP地址、广播地址与子网掩码来实现。一次性获取此类信息的C语言代码实现如下。
-
#include <stdio.h>
-
#include <string.h>
-
#include <net/if.h>
-
#include <sys/ioctl.h>
-
#include <arpa/inet.h>
-
#include <errno.h>
-
int getLocalInfo(void)
-
{
-
int fd;
-
int interfaceNum = 0;
-
struct ifreq buf[16];
-
struct ifconf ifc;
-
struct ifreq ifrcopy;
-
char mac[16] = {0};
-
char ip[32] = {0};
-
char broadAddr[32] = {0};
-
char subnetMask[32] = {0};
-
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
-
{
-
perror("socket");
-
close(fd);
-
return -1;
-
}
-
ifc.ifc_len = sizeof(buf);
-
ifc.ifc_buf = (caddr_t)buf;
-
if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc))
-
{
-
interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
-
printf("interface num = %d\n", interfaceNum);
-
while (interfaceNum-- > 0)
-
{
-
printf("\ndevice name: %s\n", buf[interfaceNum].ifr_name);
-
//ignore the interface that not up or not runing
-
ifrcopy = buf[interfaceNum];
-
if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy))
-
{
-
printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
-
close(fd);
-
return -1;
-
}
-
//get the mac of this interface
-
if (!ioctl(fd, SIOCGIFHWADDR, (char *)(&buf[interfaceNum])))
-
{
-
memset(mac, 0, sizeof(mac));
-
snprintf(mac, sizeof(mac), "%02x%02x%02x%02x%02x%02x",
-
(unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[0],
-
(unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[1],
-
(unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[2],
-
(unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[3],
-
(unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[4],
-
(unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[5]);
-
printf("device mac: %s\n", mac);
-
}
-
else
-
{
-
printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
-
close(fd);
-
return -1;
-
}
-
//get the IP of this interface
-
if (!ioctl(fd, SIOCGIFADDR, (char *)&buf[interfaceNum]))
-
{
-
snprintf(ip, sizeof(ip), "%s",
-
(char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_addr))->sin_addr));
-
printf("device ip: %s\n", ip);
-
}
-
else
-
{
-
printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
-
close(fd);
-
return -1;
-
}
-
//get the broad address of this interface
-
if (!ioctl(fd, SIOCGIFBRDADDR, &buf[interfaceNum]))
-
{
-
snprintf(broadAddr, sizeof(broadAddr), "%s",
-
(char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_broadaddr))->sin_addr));
-
printf("device broadAddr: %s\n", broadAddr);
-
}
-
else
-
{
-
printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
-
close(fd);
-
return -1;
-
}
-
//get the subnet mask of this interface
-
if (!ioctl(fd, SIOCGIFNETMASK, &buf[interfaceNum]))
-
{
-
snprintf(subnetMask, sizeof(subnetMask), "%s",
-
(char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_netmask))->sin_addr));
-
printf("device subnetMask: %s\n", subnetMask);
-
}
-
else
-
{
-
printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
-
close(fd);
-
return -1;
-
}
-
}
-
}
-
else
-
{
-
printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
-
close(fd);
-
return -1;
-
}
-
close(fd);
-
return 0;
-
}
-
int main(void)
-
{
-
getLocalInfo();
-
return 0;
-
}
使用ioctl函数虽然可以获取所有的信息,但是使用起来比较麻烦,如果不需要获取MAC地址,那么使用getifaddrs函数来获取更加方便与简洁。值得一提的是,在MacOS或iOS系统上(如iPhone程序开发),上述iotcl函数没法获得mac地址跟子网掩码,这个使用,使用getifaddrs函数便更有优势了。下面是使用getiaddrs函数获取网卡信息的C语言代码实现。
-
#include <stdio.h>
-
#include <ifaddrs.h>
-
#include <arpa/inet.h>
-
int getSubnetMask()
-
{
-
struct sockaddr_in *sin = NULL;
-
struct ifaddrs *ifa = NULL, *ifList;
-
if (getifaddrs(&ifList) < 0) return -1;
-
for (ifa = ifList; ifa != NULL; ifa = ifa->ifa_next)
-
{
-
if(ifa->ifa_addr->sa_family == AF_INET)
-
{
-
printf("\n>>> interfaceName: %s\n", ifa->ifa_name);
-
sin = (struct sockaddr_in *)ifa->ifa_addr;
-
printf(">>> ipAddress: %s\n", inet_ntoa(sin->sin_addr));
-
sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
-
printf(">>> broadcast: %s\n", inet_ntoa(sin->sin_addr));
-
sin = (struct sockaddr_in *)ifa->ifa_netmask;
-
printf(">>> subnetMask: %s\n", inet_ntoa(sin->sin_addr));
-
}
-
}
-
freeifaddrs(ifList);
-
return 0;
-
}
-
int main(void)
-
{
-
getSubnetMask();
-
return 0;
-
}
另一个使用getifaddrs()获取ip的例子,下面是man手册中的一个例子:
-
#include <arpa/inet.h>
-
#include <sys/socket.h>
-
#include <netdb.h>
-
#include <ifaddrs.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
-
int main(int argc, char *argv[])
-
{
-
struct ifaddrs *ifaddr, *ifa;
-
int family, s;
-
char host[NI_MAXHOST];
-
-
if (getifaddrs(&ifaddr) == -1) {
-
perror("getifaddrs");
-
exit(EXIT_FAILURE);
-
}
-
-
/* Walk through linked list, maintaining head pointer so we
-
* can free list later */
-
-
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
-
if (ifa->ifa_addr == NULL)
-
continue;
-
-
family = ifa->ifa_addr->sa_family;
-
-
/* Display interface name and family (including symbolic
-
* form of the latter for the common families) */
-
-
printf("%s address family: %d%s\n",
-
ifa->ifa_name, family,
-
(family == AF_PACKET) ? " (AF_PACKET)" :
-
(family == AF_INET) ? " (AF_INET)" :
-
(family == AF_INET6) ? " (AF_INET6)" : "");
-
-
/* For an AF_INET* interface address, display the address */
-
-
if (family == AF_INET || family == AF_INET6) {
-
s = getnameinfo(ifa->ifa_addr,
-
(family == AF_INET) ? sizeof(struct sockaddr_in) :
-
sizeof(struct sockaddr_in6),
-
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
-
if (s != 0) {
-
printf("getnameinfo() failed: %s\n", gai_strerror(s));
-
exit(EXIT_FAILURE);
-
}
-
printf("\taddress: <%s>\n", host);
-
}
-
}
-
-
freeifaddrs(ifaddr);
-
exit(EXIT_SUCCESS);
-
}
阅读(1760) | 评论(0) | 转发(0) |