Linux c语言获取本机 ip、子网掩码

这篇具有很好参考价值的文章主要介绍了Linux c语言获取本机 ip、子网掩码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、获取本机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 套接字提供了更详细的信息,但使用起来可能会更加复杂。文章来源地址https://www.toymoban.com/news/detail-566672.html

到了这里,关于Linux c语言获取本机 ip、子网掩码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux系统下如何修改配置 IP、网关、子网掩码、DNS 教程

    一、查看网卡信息 首先我们可以使用以下两个命令来查询网卡信息,看一下我们使用的是哪一个网卡 二、找到网卡配置文件 然后我们进入以下目录,找到上面我们用到的那个网卡文件 三、修改网卡信息 接着我们打开配置文件修改 有些新机子可能没有下面那些,我们可以新

    2024年02月12日
    浏览(29)
  • Shell脚本中获取本机ip地址,Linux获取本地ip地址

    在 Shell 脚本中获取本机 IP 地址可以通过多种方式实现,这里介绍三种常用的方法: 1. 使用 ifconfig 命令获取本机 IP 地址 ifconfig 命令可以获取本机网卡的配置信息,包括 IP 地址。可以通过 grep 命令过滤出 IP 地址信息,再使用 awk 命令提取出具体的 IP 地址。示例代码如下:

    2024年02月11日
    浏览(43)
  • 银河麒麟(linux 架构aarch64) 获取本机所有IP地址

    环境: 版本:银河麒麟桌面操作系统V10(SP1) 内核:Linux 5.4.18-35-generic CPU:Phytium,D2000/8 终端输入 uname -m 查看 架构 aarch64 在windows 上 和 银河麒麟(linux loongarch64) 使用下面的代码获取IP地址: 银河麒麟(linux) gethostname 获取不到IP地址_程序媛zcx的博客-CSDN博客_银河麒麟查看ip地

    2024年02月11日
    浏览(43)
  • qt-c++进阶1-window、linux下获取本机所有网卡ip信息、根据网卡名获取ip地址。

    例如:第一章 主要是通过qt-c++实现获取本机电脑的网卡信息或者是IP信息 总结c++获取本机网卡信息的方法 第一章:适用于windows操作系统、linux操作系统 用 QHostAddress 解析获取本机 IPV4地址 ; 用 QNetworkInterface 解析获取所有网关信息( IP地址(IPV4和IPV6) 、 子网掩码 、 广播地

    2024年02月13日
    浏览(34)
  • java:获取本机IP,Linux环境下使用InetAddress.getLocalHost()方法获得127.0.0.1

    知道InetAddress.getLocalHost()方法是可以获取本地ip的,但是在mac电脑上执行的时候,偶尔会得到127.0.0.1的输出,这样拿到本地ip很不稳定,感觉就很不靠谱了 代码 mac上输出 在 windows环境 : 使用InetAddress.getLocalHost()方法看似正常能获得本地ip,实际也有不确定性( 多网卡协同工作环

    2024年02月01日
    浏览(27)
  • ip地址、子网掩码、网段、子网划分

    Ip地址 由四个字节(32位二进制)组成,分成四组,每组八位二进制 一个简单的理解方式(并不真正是这样的):真正的网络地址划分图里右边三个框里的 例如A类,网络号是第一个八位的字节,最大是255,说明可以划分255个网络,然后容纳的主机就是后边的三个字节相乘2

    2024年02月05日
    浏览(26)
  • 广播地址和子网掩码之间有什么区别?子网掩码和ip冲突问题

    广播地址和子网掩码在计算机网络中各自扮演不同的角色,它们之间有着明显的区别。 广播地址 是一个特殊的IP地址,专门用于向网络中所有工作站发送信息。当设备发送数据包到广播地址时,所有连接到同一个网络的设备都会接收到该数据包。广播地址的存在使得向网络中

    2024年04月16日
    浏览(33)
  • IP地址及子网掩码

    IP是英文Internet Protocol的缩写,意思是“网络之间互连的协议”,也就是为计算机网络相互连接进行通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。任何厂家生产的计算机

    2024年01月19日
    浏览(26)
  • 子网掩码与IP段计算

    子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合IP地址一起使用。 子网掩码是一个32位地址,用于屏蔽IP地址的一部分以区别网络标识

    2024年02月04日
    浏览(27)
  • 详解IP地址与子网掩码

    概念 IP地址是指互联网协议地址,又叫网际协议地址。 作用 IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。 格式 IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(4个字节

    2023年04月15日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包