Linux C 获取主机网卡名及 IP 的几种方法

news/2024/11/24 13:34:25/

  在进行 Linux 网络编程时,经常会需要获取本机 IP 地址,除了常规的读取配置文件外,本文罗列几种个人所知的编程常用方法,仅供参考,如有错误请指出。

方法一:使用 ioctl() 获取本地 IP 地址

  Linux 下可以使用 ioctl() 函数以及结构体 struct ifreq 和结构体struct ifconf 来获取网络接口的各种信息。具体过程是先通过 ictol 获取本地所有接口的信息保存到 ifconf 结构中,再从其中取出每个 ifreq 表示的接口信息。

如果本机的 IP 地址绑定在第一块网卡上,则只需指定网卡名称,无需获取所有网卡的信息即可获取,见如下函数:

int get_localip(const char * eth_name, char *local_ip_addr)
{int ret = -1;register int fd;struct ifreq ifr;if (local_ip_addr == NULL || eth_name == NULL){return ret;}if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0){strcpy(ifr.ifr_name, eth_name);if (!(ioctl(fd, SIOCGIFADDR, &ifr))){ret = 0;strcpy(local_ip_addr, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));}}if (fd > 0){close(fd);}return ret;
}

如果想通过获取所有网络接口信息,示例代码如下:

#include <stdio.h>
#include <net/if.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netinet/in.h>int get_localip(const char * eth_name, char *local_ip_addr)
{int ret = -1;register int fd, intrface;struct ifreq ifr[32];struct ifconf ifc;if (local_ip_addr == NULL || eth_name == NULL){return ret;}if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0){ifc.ifc_len = sizeof ifr;ifc.ifc_buf = (caddr_t)ifr;if (!ioctl(fd, SIOCGIFCONF, (char*)&ifc)) //获取所有接口信息{intrface = ifc.ifc_len / sizeof(struct ifreq);while (intrface-- > 0){//Get IP Addressif (!(ioctl(fd, SIOCGIFADDR, (char*)&ifr[intrface]))){if(strcmp(eth_name, ifr[intrface].ifr_name) == 0){ret = 0;sprintf(local_ip_addr, "%s", inet_ntoa(((struct sockaddr_in*)(&ifr[intrface].ifr_addr))->sin_addr));break;}}}}}if (fd > 0){close(fd);}return ret;
}int main(int argc, const char **argv)
{int ret;char local_ip[20] = {0};ret = get_localip("eth0", local_ip);if (ret == 0){printf("local ip:%s\n", local_ip);}else{printf("get local ip failure\n");}return 0;
}

方法二:getsockname() 获取本地 IP 地址

  getsockname()用于获取一个已捆绑或已连接套接字的本地地址。若一个套接字与 INADDR_ANY 捆绑,也就是说该套接字可以用任意主机的地址,此时除非调用 connect()accept() 来连接,否则 getsockname() 将不会返回主机 IP 地址的任何信息。

示例代码:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>#define PORT 80
#define SERVER_IP "192.168.10.31"int main(int argc, const char **argv)
{int ret = -1;socklen_t len;char buf[30] = {0};struct sockaddr_in server_addr, local_addr;int fd = socket(AF_INET, SOCK_STREAM, 0);//int fd = socket(AF_INET, SOCK_DGRAM, 0);if (fd <= 0){printf("fail to creat socket\n");return -1;}memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port   = htons(PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);if(connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr))<0){printf("connect error!!!\n");goto end;}len = sizeof(local_addr);memset(&local_addr,  0, sizeof(local_addr));ret = getsockname(fd, (struct sockaddr*)&local_addr, &len);if (ret == 0){printf("local ip is %s, local port is %d\n", inet_ntop(AF_INET, &local_addr.sin_addr, buf, sizeof(buf)), ntohs(local_addr.sin_port));}else{printf("getsockname failed, error=%d\n", errno);}end:if (fd){close(fd);}return ret;
}

方法三:getaddrinfo() 获取本地 IP 地址

  getaddrinfo() 可以完成网络主机中主机名和服务名到地址的映射,但是一般不能用来获取本地 IP 地址,当它用来获取本地 IP 地址时,返回的一般是 127.0.0.1 本地回环地址,且该函数仅仅支持 IPv4

示例代码:

#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>// 获取本地IP时,一般都是127.0.0.1
int main(int argc, const char **argv)
{int ret;char host_name[128] = {0};struct addrinfo *res, *cur;struct sockaddr_in *addr;if (gethostname(host_name, sizeof(host_name)) < 0){printf("gethostname error\n");return -1;}ret = getaddrinfo(host_name, NULL, NULL, &res);if (ret != 0){printf("Error: error in getaddrinfo on hostname: %s\n", gai_strerror(ret));return -1;}for(cur = res; cur != NULL; cur = cur->ai_next){if(cur->ai_family == AF_INET){addr = (struct sockaddr_in*)cur->ai_addr;printf("local ip:%s\n", inet_ntoa(addr->sin_addr));}//char host[1024] = {0};//ret = getnameinfo(cur->ai_addr, cur->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);//if(ret != 0)//{//	printf("getnameinfo: %s\n", gai_strerror(ret));//}//else//{//	printf("ip: %s\n", host);//}}freeaddrinfo(res);return 0;
}

方法四:gethostbyname() 获取本地 IP 地址

  gethostbyname()getaddrinfo() 的功能类似,一般用于通过主机名或者服务名,比如域名来获取主机的 IP 地址。但是要想获取本地 IP 地址的时候,一般获取的是回环地址 127.0.0.1

示例代码:

#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>// 获取本地IP时,一般都是127.0.0.1
int main(int argc, const char **argv)
{int i = 0;char host_name[128] = {0};struct hostent *hptr;if (gethostname(host_name, sizeof(host_name)) < 0){printf("gethostname error\n");return -1;}if ((hptr=gethostbyname(host_name)) == NULL){printf("gethostbyname error\n");return -1;}while(hptr->h_addr_list[i] != NULL){printf("hostname: %s\n", hptr->h_name);printf("      ip: %s\n", inet_ntoa(*(struct in_addr*)hptr->h_addr_list[i]));i++;}return 0;
}

方法五:通过 getifaddrs() 获取本地 IP 地址

代码来自StackOverflow:http://stackoverflow.com/questions/212528/linux-c-get-the-ip-address-of-local-computer

这里解释一下代码中的 INET_ADDRSTRLENINET6_ADDRSTRLEN ,该宏变量是定义在 netinet/in.h 头文件中:

// FILE: netinet/in.h#define INET_ADDRSTRLEN 16 /* for IPv4 dotted-decimal */#define INET6_ADDRSTRLEN 46 /* for IPv6 hex string */

示例代码:

#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>int main (int argc, const char * argv[])
{struct ifaddrs * ifAddrStruct=NULL;struct ifaddrs * ifa=NULL;void * tmpAddrPtr=NULL;getifaddrs(&ifAddrStruct);for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next){if (!ifa->ifa_addr){continue;}if (ifa->ifa_addr->sa_family == AF_INET) // check it is IP4{// is a valid IP4 AddresstmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;char addressBuffer[INET_ADDRSTRLEN];inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);}else if (ifa->ifa_addr->sa_family == AF_INET6) // check it is IP6{// is a valid IP6 AddresstmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;char addressBuffer[INET6_ADDRSTRLEN];inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);}}if (ifAddrStruct!=NULL){freeifaddrs(ifAddrStruct);}return 0;
}

方法六:通过 popen() 调用 ifconfig 获取本地 IP 地址

  用popen() 建立一个管道,管道的一端执行命令 ifconfig,管道的另一端读取收到的数据并进行相应的解析。这种方法需要执行 shell 命令,配合正则表达式,效率较低,一般不采用。而这种方式其实更倾向于配置,原因就是使用简单。

示例代码:

#include <stdio.h>
#include <stdlib.h>#define ETH_NAME	"ens33"int main(int argc, const char *argv[])
{FILE *fp;char buf[256] = {0};char command[256] = {0};//char *fmt = "ifconfig %s|sed -n '2p'|sed -n 's#^.*dr:##gp'|sed -n 's#B.*$##gp'";char *fmt = "ifconfig %s|grep 'inet addr'|awk '{ print $2}' | awk -F: '{print $2}'";snprintf(command, sizeof(command), fmt, ETH_NAME);if((fp = popen(command, "r")) == NULL){perror("Fail to popen\n");return -1;}while(fgets(buf, sizeof(buf), fp) != NULL){printf("%s", buf);}pclose(fp);return 0;
}

参考文章

[1] https://blog.csdn.net/bailyzheng/article/details/7489656
[2] https://blog.csdn.net/k346k346/article/details/48231933
[3] https://blog.csdn.net/zhongmushu/article/details/89944990


http://www.ppmy.cn/news/1001407.html

相关文章

【Spring Boot】请求参数传json数组,后端采用(pojo)新增案例(103)

请求参数传json数组&#xff0c;后端采用&#xff08;pojo&#xff09;接收的前提条件&#xff1a; 1.pom.xml文件加入坐标依赖&#xff1a;jackson-databind 2.Spring Boot 的启动类加注解&#xff1a;EnableWebMvc 3.Spring Boot 的Controller接受参数采用&#xff1a;Reque…

django使用ztree实现树状结构效果,子节点实现动态加载(l懒加载)

一、实现的效果 由于最近项目中需要实现树状结构的效果,考虑到ztree这个组件大家用的比较多,因此打算在django项目中集成ztree来实现树状的效果。最终实现的示例效果如下: 点击父节点,如果有子节点,则从后台动态请求数据,然后显示出子节点的数据。 二、实现思路 …

JVM面试突击班2

JVM面试突击班2 对象被判定为不可达对象之后就“死”了吗 对象的生命周期 创建阶段 &#xff08;1&#xff09;为对象分配存储空间 &#xff08;2&#xff09;开始构造对象 &#xff08;3&#xff09;从超类到子类对static成员进行初始化 &#xff08;4&#xff09;超类成…

SAS-数据集SQL垂直(纵向)合并

一、SQL垂直合并的基本语法 一个selectt对应一个表&#xff0c;select之间用set-operator连接&#xff0c;set-operator包括&#xff1a;except&#xff08;期望&#xff09;、intersect&#xff08;相交&#xff09;、union&#xff08;合并&#xff09;&#xff0c;outer un…

Spring mvc:SpringServletContainerInitializer

SpringServletContainerInitializer实现了Servlet3.0规范中定义的ServletContainerInitializer&#xff1a; public interface ServletContainerInitializer {void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException; }SpringServletCont…

2023河南萌新联赛第(四)场 L.7是大奖?(数位DP基础)

文章目录 题目大意题解参考代码总结 题目大意 ( 1 ≤ l , r ≤ 1 0 18 ) (1\leq l,r\leq 10^{18}) (1≤l,r≤1018) 题解 由题目可得 ①&#xff1a;统计数字出现次数&#xff1b; ②&#xff1a;直接暴力计算无法得出&#xff1b; ③&#xff1a;输入给定区间。 满足使用数位…

如何从 html 页面调用在 javascript 模块 (type=module) 中声明的函数

首先&#xff0c;必须明确导出您的功能 export function greet() {alert("Hello from module"); } 其次&#xff0c;模块有它自己的范围&#xff08;这是模块的全部意义&#xff09;&#xff0c;因此您需要将函数添加到全局范围。因此&#xff0c;要做到这一点&…

企业真实的自动化框架?资深8年测试是如何设计实施的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 什么是框架&#…