一、目的
在实际项目中需要获取设备的IP地址然后通过广播的形式通知局域网内的其他设备。
二、介绍
方法一
通过ioctl方式获取SIOCGIFADDR信息
/** C Program to Get IP Address*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>int main(int argc, char **argv)
{int n;struct ifreq ifr;char *inf = argv[1];n = socket(AF_INET, SOCK_DGRAM, 0);//Type of address to retrieve - IPv4 IP addressifr.ifr_addr.sa_family = AF_INET;//Copy the interface name in the ifreq structurestrncpy(ifr.ifr_name, inf, IFNAMSIZ - 1);ioctl(n, SIOCGIFADDR, &ifr);close(n);//display resultprintf("IP Address is %s - %s\n" , inf , inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr) );return 0;
}
gcc getip.c -o getip
这种方法的前提是必须知道网络接口名称,比如enp1s0或者eth0
参考资料
netdevice(7) - Linux manual pagehttps://man7.org/linux/man-pages/man7/netdevice.7.html
方法二
通过函数getaddrinfo实现
在正式介绍之前,我们先介绍一下ifconfig -a的输出各个字段的含义
#include <sys/types.h>
#include <ifaddrs.h>/*
获取网络接口链表
*/
int getifaddrs(struct ifaddrs **ifap);/*
释放网络接口链表
*/
void freeifaddrs(struct ifaddrs *ifa);struct ifaddrs {struct ifaddrs *ifa_next; /* Next item in list */char *ifa_name; /* Name of interface */unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */struct sockaddr *ifa_addr; /* Address of interface */struct sockaddr *ifa_netmask; /* Netmask of interface */union {struct sockaddr *ifu_broadaddr;/* Broadcast address of interface */struct sockaddr *ifu_dstaddr;/* Point-to-point destination address */} ifa_ifu;#define ifa_broadaddr ifa_ifu.ifu_broadaddr#define ifa_dstaddr ifa_ifu.ifu_dstaddrvoid *ifa_data; /* Address-specific data */};
各个字段含义:
ifa_next:下一个接口的地址
ifa_name:接口名称,例如"eth0"、"lo"
ifa_flags:接口属性状态标志
ifa_addr:接口的IP地址(ipv4/ipv6),当接口不在工作时该指针为NULL
ifa_netmask:接口的子网掩码
ifa_broadaddr:如果支持广播,此字段记录广播地址信息
ifa_dstaddr:如果支持点对点通信,此字段记录对端地址
三、实战
#define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>int main(int argc, char *argv[])
{struct ifaddrs *ifaddr, *ifa;int family, s, n;char host[NI_MAXHOST];if (getifaddrs(&ifaddr) == -1) {perror("getifaddrs");exit(EXIT_FAILURE);}/* Walk through linked list, maintaining head pointer so wecan free list later */#if 1for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {if (ifa->ifa_addr == NULL)continue;printf("======1\n");family = ifa->ifa_addr->sa_family;/* Display interface name and family (including symbolicform of the latter for the common families) */printf("%-8s %s (%d)\n",ifa->ifa_name,(family == AF_PACKET) ? "AF_PACKET" :(family == AF_INET) ? "AF_INET" :(family == AF_INET6) ? "AF_INET6" : "???",family);/* For an AF_INET* interface address, display the address */printf("======2\n");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("\t\taddress: <%s>\n", host);} else if (family == AF_PACKET && ifa->ifa_data != NULL) {struct rtnl_link_stats *stats = ifa->ifa_data;printf("\t\ttx_packets = %10u; rx_packets = %10u\n""\t\ttx_bytes = %10u; rx_bytes = %10u\n",stats->tx_packets, stats->rx_packets,stats->tx_bytes, stats->rx_bytes);}printf("======3\n");}
#elsefor (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {if (ifa->ifa_addr == NULL)continue;family = ifa->ifa_addr->sa_family;unsigned int flags = ifa->ifa_flags;if (family == AF_INET && (flags & (IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST))) {if (0 == strcmp(ifa->ifa_name, argv[1])) {s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST,NULL, 0, NI_NUMERICHOST);if (s != 0) {printf("getnameinfo() failed: %s\n", gai_strerror(s));exit(EXIT_FAILURE);}printf("\t\taddress: <%s>\n", host);}}}
#endiffreeifaddrs(ifaddr);exit(EXIT_SUCCESS);
}