Chinaunix首页 | 论坛 | 博客
  • 博客访问: 66503
  • 博文数量: 39
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 226
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-04 09:56
个人简介

小小博客,不足为外人道

文章分类

全部博文(39)

分类: C/C++

2015-02-04 16:30:49

在Linux下开发网络程序时,经常会遇到需要取本地网络接口名、IP、广播地址、子网掩码或者MAC地址等信息的需求,最常见的办法是配合宏SIOCGIFHWADDR、SIOCGIFADDR、SIOCGIFBRDADDR与SIOCGIFNETMASK作为参数调用函数ioctl分别获得MAC地址、IP地址、广播地址与子网掩码来实现。一次性获取此类信息的C语言代码实现如下。




点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <net/if.h>
  4. #include <sys/ioctl.h>
  5. #include <arpa/inet.h>
  6. #include <errno.h>
  7. int getLocalInfo(void)
  8. {
  9.    int fd;
  10.    int interfaceNum = 0;
  11.    struct ifreq buf[16];
  12.    struct ifconf ifc;
  13.    struct ifreq ifrcopy;
  14.    char mac[16] = {0};
  15.    char ip[32] = {0};
  16.    char broadAddr[32] = {0};
  17.    char subnetMask[32] = {0};
  18.    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  19.    {
  20.       perror("socket");
  21.       close(fd);
  22.       return -1;
  23.    }
  24.    ifc.ifc_len = sizeof(buf);
  25.    ifc.ifc_buf = (caddr_t)buf;
  26.    if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc))
  27.    {
  28.       interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
  29.       printf("interface num = %d\n", interfaceNum);
  30.       while (interfaceNum-- > 0)
  31.       {
  32.              printf("\ndevice name: %s\n", buf[interfaceNum].ifr_name);
  33.              //ignore the interface that not up or not runing
  34.              ifrcopy = buf[interfaceNum];
  35.              if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy))
  36.              {
  37.                 printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
  38.                 close(fd);
  39.                 return -1;
  40.              }
  41.              //get the mac of this interface
  42.              if (!ioctl(fd, SIOCGIFHWADDR, (char *)(&buf[interfaceNum])))
  43.              {
  44.                 memset(mac, 0, sizeof(mac));
  45.                 snprintf(mac, sizeof(mac), "%02x%02x%02x%02x%02x%02x",
  46.                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[0],
  47.                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[1],
  48.                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[2],
  49.                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[3],
  50.                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[4],
  51.                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[5]);
  52.                 printf("device mac: %s\n", mac);
  53.              }
  54.             else
  55.             {
  56.                 printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
  57.                 close(fd);
  58.                 return -1;
  59.             }
  60.             //get the IP of this interface
  61.             if (!ioctl(fd, SIOCGIFADDR, (char *)&buf[interfaceNum]))
  62.             {
  63.                 snprintf(ip, sizeof(ip), "%s",
  64.                             (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_addr))->sin_addr));
  65.                 printf("device ip: %s\n", ip);
  66.             }
  67.             else
  68.             {
  69.                 printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
  70.                 close(fd);
  71.                 return -1;
  72.             }
  73.             //get the broad address of this interface
  74.             if (!ioctl(fd, SIOCGIFBRDADDR, &buf[interfaceNum]))
  75.             {
  76.                 snprintf(broadAddr, sizeof(broadAddr), "%s",
  77.                             (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_broadaddr))->sin_addr));
  78.                 printf("device broadAddr: %s\n", broadAddr);
  79.             }
  80.             else
  81.             {
  82.                 printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
  83.                 close(fd);
  84.                 return -1;
  85.             }
  86.             //get the subnet mask of this interface
  87.             if (!ioctl(fd, SIOCGIFNETMASK, &buf[interfaceNum]))
  88.             {
  89.                 snprintf(subnetMask, sizeof(subnetMask), "%s",
  90.                             (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_netmask))->sin_addr));
  91.                 printf("device subnetMask: %s\n", subnetMask);
  92.             }
  93.             else
  94.             {
  95.                 printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
  96.                 close(fd);
  97.                 return -1;
  98.             }
  99.         }
  100.     }
  101.     else
  102.     {
  103.         printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
  104.         close(fd);
  105.         return -1;
  106.     }
  107.     close(fd);
  108.     return 0;
  109. }
  110. int main(void)
  111. {
  112.     getLocalInfo();
  113.     return 0;
  114. }


使用ioctl函数虽然可以获取所有的信息,但是使用起来比较麻烦,如果不需要获取MAC地址,那么使用getifaddrs函数来获取更加方便与简洁。值得一提的是,在MacOS或iOS系统上(如iPhone程序开发),上述iotcl函数没法获得mac地址跟子网掩码,这个使用,使用getifaddrs函数便更有优势了。下面是使用getiaddrs函数获取网卡信息的C语言代码实现。


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <ifaddrs.h>
  3. #include <arpa/inet.h>
  4. int getSubnetMask()
  5. {
  6.     struct sockaddr_in *sin = NULL;
  7.     struct ifaddrs *ifa = NULL, *ifList;
  8.     if (getifaddrs(&ifList) < 0) return -1;
  9.     for (ifa = ifList; ifa != NULL; ifa = ifa->ifa_next)
  10.     {
  11.         if(ifa->ifa_addr->sa_family == AF_INET)
  12.         {
  13.             printf("\n>>> interfaceName: %s\n", ifa->ifa_name);
  14.             sin = (struct sockaddr_in *)ifa->ifa_addr;
  15.             printf(">>> ipAddress: %s\n", inet_ntoa(sin->sin_addr));
  16.             sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
  17.             printf(">>> broadcast: %s\n", inet_ntoa(sin->sin_addr));
  18.             sin = (struct sockaddr_in *)ifa->ifa_netmask;
  19.             printf(">>> subnetMask: %s\n", inet_ntoa(sin->sin_addr));
  20.         }
  21.     }
  22.     freeifaddrs(ifList);
  23.     return 0;
  24. }
  25. int main(void)
  26. {
  27.     getSubnetMask();
  28.     return 0;
  29. }


另一个使用getifaddrs()获取ip的例子,下面是man手册中的一个例子:



点击(此处)折叠或打开

  1. #include <arpa/inet.h>
  2. #include <sys/socket.h>
  3. #include <netdb.h>
  4. #include <ifaddrs.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>

  8. int main(int argc, char *argv[])
  9. {
  10.     struct ifaddrs *ifaddr, *ifa;
  11.     int family, s;
  12.     char host[NI_MAXHOST];

  13.     if (getifaddrs(&ifaddr) == -1) {
  14.         perror("getifaddrs");
  15.         exit(EXIT_FAILURE);
  16.     }

  17.     /* Walk through linked list, maintaining head pointer so we
  18.     * can free list later */

  19.     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  20.         if (ifa->ifa_addr == NULL)
  21.             continue;

  22.         family = ifa->ifa_addr->sa_family;

  23.         /* Display interface name and family (including symbolic
  24.         * form of the latter for the common families) */

  25.         printf("%s address family: %d%s\n",
  26.                 ifa->ifa_name, family,
  27.                 (family == AF_PACKET) ? " (AF_PACKET)" :
  28.                 (family == AF_INET) ? " (AF_INET)" :
  29.                 (family == AF_INET6) ? " (AF_INET6)" : "");

  30.         /* For an AF_INET* interface address, display the address */

  31.         if (family == AF_INET || family == AF_INET6) {
  32.             s = getnameinfo(ifa->ifa_addr,
  33.                     (family == AF_INET) ? sizeof(struct sockaddr_in) :
  34.                     sizeof(struct sockaddr_in6),
  35.                     host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  36.             if (s != 0) {
  37.                 printf("getnameinfo() failed: %s\n", gai_strerror(s));
  38.                 exit(EXIT_FAILURE);
  39.             }
  40.             printf("\taddress: <%s>\n", host);
  41.         }
  42.     }

  43.     freeifaddrs(ifaddr);
  44.     exit(EXIT_SUCCESS);
  45. }


阅读(708) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~