一、目的
在实际项目中需要获取设备的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 address
ifr.ifr_addr.sa_family = AF_INET;
//Copy the interface name in the ifreq structure
strncpy(ifr.ifr_name, inf, IFNAMSIZ - 1);
ioctl(n, SIOCGIFADDR, &ifr);
close(n);
//display result
printf("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_dstaddr
void *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 we
can free list later */
#if 1
for (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 symbolic
form 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");
}
#else
for (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);
}
}
}
#endif
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}