一、获取本机ip
1.1 获取指定网卡的 ip
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
int main(int argc, char *argv[]) {
if(argc < 2){
printf("please input correct , argc = %d\n", argc);
return -1;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket() error");
return -1;
}
const char *network_card_name = argv[1];
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, network_card_name, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {
perror("ioctl() error");
close(sockfd);
return -1;
}
struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
char ip_address[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin->sin_addr, ip_address, sizeof(ip_address));
printf("IP Address: %s\n", ip_address);
close(sockfd);
return 0;
}
ifconfig 命令查询本机的网络接口名称,然后运行程序时加上输入参数:网络接口名称。
./a.out network_card_name
使用 ioctl() 函数获取本机IP地址的方法。该方法通过查询指定网络接口的IP地址,获取本机的IP地址。
(1)创建一个基于IP协议的socket。
创建了一个套接字,使用了 socket() 系统调用。socket() 系统调用的第一个参数指定了套接字的地址族,这里指定为 AF_INET 表示使用 IPv4 地址。第二个参数指定了套接字的类型,这里指定为 SOCK_DGRAM 表示使用数据报(Datagram)传输方式。第三个参数可以用来指定协议类型,这里设置为0,表示使用默认协议。
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket() error");
return -1;
}
(2)准备一个 ifreq 结构体,用于保存网络接口的信息。
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, network_card_name, IFNAMSIZ - 1);
struct ifreq 是一个用于保存网络接口信息的结构体,在 Linux 中定义在 net/if.h 中,它的定义如下:
/* Interface request structure used for socket ioctl's. All interface ioctl's must have parameter definitions which begin with ifr_name. The remainder may be interface specific. */
struct ifreq
{
# define IFHWADDRLEN 6
# define IFNAMSIZ IF_NAMESIZE
union
{
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
} ifr_ifrn;
union
{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short int ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
__caddr_t ifru_data;
} ifr_ifru;
};
其中,ifrn_name 保存网络接口的名称,ifru_addr 保存网络接口的IP地址,ifru_hwaddr 保存网络接口的MAC地址,ifru_flags 保存网络接口的状态标志等。实际上,struct ifreq 的成员 ifru_addr、ifru_dstaddr、ifru_broadaddr、ifru_netmask、ifru_hwaddr 等都是 sockaddr 结构体的变体,可以保存不同类型的地址信息。
在使用 ioctl() 函数查询网络接口信息时,我们可以将需要查询的网络接口名称保存在 ifrn_name 中,然后将 struct ifreq 结构体作为 ioctl() 函数的参数传递给内核,内核会将查询结果保存在 ifru_addr、ifru_hwaddr 等成员中。我们可以根据实际需要,从相应的成员中提取出相应的地址信息。
需要注意的是,由于 ifru_addr、ifru_dstaddr、ifru_broadaddr、ifru_netmask、ifru_hwaddr 等成员都是 sockaddr 结构体的变体,因此在使用时需要根据实际情况选择合适的成员,以免出现类型错误的情况。
(3)调用 ioctl() 函数查询网络接口的IP地址。
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {
perror("ioctl() error");
close(sockfd);
return -1;
}
在 Linux 中,网络接口信息保存在内核中,可以通过 ioctl() 系统调用来查询和设置网络接口的信息。ioctl() 系统调用提供了一种通用的接口,可以用来查询和设置各种设备的信息,包括网络接口、硬盘、串口等。
对于网络接口,ioctl() 函数主要用于查询和设置以下信息:
网络接口的IP地址、子网掩码、广播地址、MAC地址等;
网络接口的状态,如是否启用、是否混杂模式等;
网络接口的MTU(最大传输单元)等。
在使用 ioctl() 函数查询网络接口信息时,需要使用 struct ifreq 结构体来保存查询和设置的参数。该结构体包含了需要查询和设置的参数,如网络接口的名称、IP地址、MAC地址等。在查询时,我们可以将需要查询的网络接口名称保存在 ifreq 结构体中,然后将该结构体作为 ioctl() 函数的参数传递给内核,内核会将查询结果保存在相应的成员中,如 ifr_addr、ifr_hwaddr 等成员中。我们可以根据实际需要,从相应的成员中提取出相应的地址信息。
需要注意的是,由于网络接口的地址类型可能不同,如 IPv4、IPv6 和 MAC 地址等,因此在使用 struct ifreq 结构体时需要根据实际情况选择合适的成员,以免出现类型错误的情况。
总之,ioctl() 函数提供了一种通用的接口,可以用来查询和设置各种设备的信息,包括网络接口。在使用 ioctl() 函数查询网络接口信息时,需要使用 struct ifreq 结构体来保存查询和设置的参数,根据实际情况选择合适的成员,以提取出相应的地址信息。
(4)从 ifr 结构体中获取 IP 地址,并将其转换为字符串格式
struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
char ip_address[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin->sin_addr, ip_address, sizeof(ip_address));
struct sockaddr_in:
struct sockaddr_in 是一个用于描述 IPv4 地址的结构体,在 Linux 中定义在 netinet/in.h 中。其定义如下:
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
其中,sin_family 是地址族,固定为 AF_INET 表示 IPv4 地址族。sin_port 是端口号,用于标识网络连接的端口。sin_addr 是一个结构体,用于保存 IPv4 地址。sin_zero 是一个用于填充结构体大小的数组,以使 struct sockaddr_in 和 struct sockaddr 相同大小。
需要注意的是,struct in_addr 结构体是 unsigned long 类型的别名,用于保存 IPv4 地址。IPv4 地址是一个 32 位二进制数,通常用点分十进制表示法来表示。
总之,struct sockaddr_in 结构体是用于描述 IPv4 地址的结构体,包括地址族、端口号、IPv4 地址等成员,并与 struct sockaddr 相同大小。在使用套接字编程时,我们可以使用 struct sockaddr_in 结构体来表示 IPv4 地址。
inet_ntop 函数:
/* Convert a Internet address in binary network format for interface type AF in buffer starting at CP to presentation form and place result in buffer of length LEN astarting at BUF. */
extern const char *inet_ntop (int __af, const void *__restrict __cp,
char *__restrict __buf, socklen_t __len)
__THROW;
这是 inet_ntop() 函数的函数原型,定义在 arpa/inet.h 头文件中。该函数用于将网络字节序的二进制IP地址转换成点分十进制字符串表示。
函数原型中,__af 参数表示地址族,可以是 AF_INET 或 AF_INET6。__cp 参数是一个指向二进制IP地址的缓冲区的指针,缓冲区长度和地址族相关。__buf 参数是一个指向用于保存转换后的点分十进制字符串表示的目标缓冲区的指针,__len 参数表示目标缓冲区的长度。
函数返回值为一个指向字符串的指针,该字符串表示转换后的IP地址。如果转换成功,则返回指向目标缓冲区的指针;如果转换失败,则返回 NULL。
需要注意的是,inet_ntop() 函数只能将网络字节序的二进制IP地址转换成点分十进制字符串表示,如果需要将主机字节序的二进制IP地址转换成点分十进制字符串表示,则需要先将其转换为网络字节序,再调用 inet_ntop() 函数。
总之,inet_ntop() 函数用于将网络字节序的二进制IP地址转换成点分十进制字符串表示,并将结果保存在目标缓冲区中。该函数在套接字编程中经常用于将网络地址转换为可读的形式。
1.2 获取本机所有网络接口 ip 地址
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
int main() {
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
char ip_address[INET_ADDRSTRLEN];
if (getifaddrs(&ifap) == -1) {
perror("getifaddrs() error");
return -1;
}
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr != NULL && ifa->ifa_addr->sa_family == AF_INET) {
sa = (struct sockaddr_in *) ifa->ifa_addr;
inet_ntop(AF_INET, &sa->sin_addr, ip_address, sizeof(ip_address));
printf("%s: %s\n", ifa->ifa_name, ip_address);
}
}
freeifaddrs(ifap);
return 0;
}
使用 getifaddrs() 函数查询系统中所有网络接口的 IP 地址。
该程序首先调用 getifaddrs() 函数获取系统中所有网络接口的信息,然后遍历链表,对每个网络接口的地址信息进行处理。对于 IPv4 地址,程序将其转换成点分十进制字符串,并打印出网络接口的名称和 IP 地址。
最后,程序调用 freeifaddrs() 函数释放内存,然后返回 0。
需要注意的是,getifaddrs() 函数在查询成功后会返回一个链表,链表中的每个节点都保存了一个网络接口的信息,包括网络接口的名称、IP 地址、MAC 地址等。在遍历链表时,需要判断每个节点中的地址类型,以便正确地提取出 IP 地址。
(1)
getifaddrs() 函数是一个用于获取主机上所有网络接口信息的函数。
man getifaddrs
NAME
getifaddrs, freeifaddrs - get interface addresses
SYNOPSIS
#include <sys/types.h>
#include <ifaddrs.h>
int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa);
其中,ifap 是一个指向指针的指针,用于返回指向 struct ifaddrs 结构体链表的指针。该结构体包含了与网络接口相关的信息,例如接口名称、IPv4/IPv6 地址、网络掩码、MAC 地址等。
getifaddrs() 函数返回值为 0 表示成功,-1 表示失败,并设置对应的 errno 值。如果成功,函数将返回一个指向 struct ifaddrs 结构体链表的指针,需要使用 freeifaddrs() 函数释放该结构体链表所占用的内存。
需要注意的是,getifaddrs() 函数返回的链表包含了主机上所有网络接口的信息,包括未启用的接口,因此需要遍历整个链表并检查每个接口的状态和属性。
总之,getifaddrs() 函数是一个用于获取主机上所有网络接口信息的函数,可以通过遍历返回的 struct ifaddrs 结构体链表获取每个接口的信息。在套接字编程中,该函数经常用于获取本机的网络信息以及与网络接口相关的属性。
(2)
struct ifaddrs 是一个用于保存网络接口信息的结构体,在 Linux 中定义在 ifaddrs.h 中。它的定义如下:
/* The `getifaddrs' function generates a linked list of these structures. Each element of the list describes one network interface. */
struct ifaddrs
{
struct ifaddrs *ifa_next; /* Pointer to the next structure. */
char *ifa_name; /* Name of this network interface. */
unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */
struct sockaddr *ifa_addr; /* Network address of this interface. */
struct sockaddr *ifa_netmask; /* Netmask of this interface. */
union
{
/* At most one of the following two is valid. If the IFF_BROADCAST bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid. It is never the case that both these bits are set at once. */
struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */
} ifa_ifu;
/* These very same macros are defined by <net/if.h> for `struct ifaddr'. So if they are defined already, the existing definitions will be fine. */
# ifndef ifa_broadaddr
# define ifa_broadaddr ifa_ifu.ifu_broadaddr
# endif
# ifndef ifa_dstaddr
# define ifa_dstaddr ifa_ifu.ifu_dstaddr
# endif
void *ifa_data; /* Address-specific data (may be unused). */
};
其中,ifa_next 是指向链表中下一个节点的指针,ifa_name 保存网络接口的名称,ifa_flags 保存网络接口的状态标志,如是否启用、是否混杂模式等。ifa_addr 保存网络接口的IP地址,ifa_netmask 保存网络接口的子网掩码。ifu_broadaddr 和 ifu_dstaddr 分别保存网络接口的广播地址和目标地址。
需要注意的是,由于 ifu_broadaddr 和 ifu_dstaddr 是联合体,只能同时保存其中的一个成员,具体保存哪个成员取决于网络接口的类型。如果网络接口是广播类型,则 ifu_broadaddr 成员保存广播地址;如果是点对点类型,则 ifu_dstaddr 成员保存目标地址。
总之,struct ifaddrs 结构体用于保存网络接口信息,包括名称、状态、IP地址、子网掩码、广播地址和目标地址等。在使用 getifaddrs() 函数查询网络接口信息时,该函数会返回一个链表,链表中的每个节点都保存了一个网络接口的信息,并通过 struct ifaddrs 结构体来描述。我们可以遍历链表,对每个节点的地址信息进行处理。
二、获取本机子网掩码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
int main(int argc, char *argv[]) {
if(argc < 2){
printf("please input correct , argc = %d\n", argc);
return -1;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket() error");
return -1;
}
const char *network_card_name = argv[1];
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, network_card_name, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0) {
perror("ioctl() error");
close(sockfd);
return -1;
}
struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_netmask;
char netmask[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin->sin_addr, netmask, sizeof(netmask));
printf("Netmask: %s\n", netmask);
close(sockfd);
return 0;
}
和 1.1 方案一样,不在描述。
三、获取网络接口信息
上面几个例子说明了几种获取网络接口信息的方案,下面来描述一下Linux 下获取网络接口信息的一些常见方案。
在 Linux 中,获取网络接口信息的常用方案有以下几种:
(1)getifaddrs() 函数:这是一个标准的 POSIX 函数,可以用于获取系统上的网络接口信息。它返回一个指向 struct ifaddrs 结构体的链表,其中包含了每个网络接口的信息,如接口名称、IP 地址、掩码和 MAC 地址等。
(2)ioctl() 函数:这是一个通用的 I/O 控制系统调用,可以通过使用 SIOCGIFCONF 命令来获取网络接口信息。该命令返回一个 struct ifconf 结构体,其中包含了多个 struct ifreq 结构体组成的数组,每个 struct ifreq 结构体包含了一个网络接口的信息,例如接口名称、IP 地址、掩码和 MAC 地址等。
(3)sysfs 文件系统:在 Linux 中,每个网络接口都对应一个 sysfs 目录,其中包含了该接口的一些属性信息,例如接口名称、MAC 地址、速度、状态等。可以通过在 sysfs 文件系统中查找对应的目录并读取相应的文件获取网络接口信息。例如,接口 eth0 的 sysfs 目录为 /sys/class/net/eth0,其中包含了名为 address 的文件,其内容即为该接口的 MAC 地址。
(4)netlink 套接字:netlink 是一种用于内核与用户空间之间通信的机制,可以使用 netlink 套接字获取网络接口信息。在 Linux 中,网络接口的信息可以通过 NETLINK_ROUTE 协议的 RTM_GETLINK 命令获取,该命令返回一个 struct ifinfomsg 结构体,其中包含了网络接口的属性信息,例如接口名称、MAC 地址、状态、速度等。
这些方案各有优缺点,选择方案需要根据具体需求和应用场景。例如,getifaddrs() 是一个高级 API,易于使用且提供了大量信息,而 ioctl() 提供了更精细的控制,可以获取 getifaddrs() 无法获取的信息。sysfs 文件系统和 netlink 套接字提供了更详细的信息,但使用起来可能会更加复杂。
今天的文章linux c获取mac地址_已知ip如何求子网掩码「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/85021.html