C语言动态获取设备的网络接口名称和状态以及对应的IP地址

一、目的

        在实际项目中需要获取设备的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 pageicon-default.png?t=N658https://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);
}

        

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
获取网络设备信息,需要使用系统提供的网络编程API,下面是一个简单的例子,可以获取本机的所有网络设备信息: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <ifaddrs.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> int main() { struct ifaddrs *if_list; struct ifaddrs *if_node; char ip_addr[INET_ADDRSTRLEN]; char mac_addr[18]; int i, family, s; if (getifaddrs(&if_list) == -1) { perror("getifaddrs"); return -1; } i = 0; for (if_node = if_list; if_node != NULL; if_node = if_node->ifa_next) { if (if_node->ifa_addr == NULL) continue; family = if_node->ifa_addr->sa_family; if (family == AF_INET || family == AF_INET6) { s = getnameinfo(if_node->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip_addr, INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); if (s != 0) { printf("getnameinfo() failed: %s\n", gai_strerror(s)); return -1; } printf("%d: %s\n", ++i, if_node->ifa_name); printf(" IP address: %s\n", ip_addr); if (family == AF_PACKET) { struct sockaddr_ll *sll = (struct sockaddr_ll*)if_node->ifa_addr; int j; for (j = 0; j < 6; j++) { sprintf(mac_addr + 3 * j, "%02X:", (unsigned char)sll->sll_addr[j]); } mac_addr[17] = '\0'; printf(" MAC address: %s\n", mac_addr); } } } freeifaddrs(if_list); return 0; } ``` 这个程序会遍历所有的网络设备,并输出设备名称IP地址和MAC地址。其中,`getifaddrs()`函数可以获取当前主机的所有网络接口的信息,返回的是一个链表,每个节点代表一个网络接口。对于每个节点,可以通过`ifa_name`字段获取接口名称,通过`ifa_addr`字段获取接口地址,然后根据地址类型进行不同的处理。如IPv4地址和IPv6地址可以通过`inet_ntop()`函数将二进制地址转换成字符串形式,而MAC地址需要通过`sll_addr`字段获取

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值