获取 Linux 上接口的 IP 地址
- 2024-10-17 08:47:00
- admin 原创
- 68
问题描述:
如何从 C 代码获取 Linux 上接口的IPv4地址?
例如,我想要获取分配给 eth0 的 IP 地址(如果有)。
解决方案 1:
尝试一下:
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int
main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
/* display result */
printf("%s
", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
return 0;
}
代码示例取自这里。
解决方案 2:
ioctl()
除了Filip 演示的方法之外,您还可以使用getifaddrs ()。手册页底部有一个示例程序。
解决方案 3:
如果你正在寻找特定接口(比如wlan0)的地址(IPv4) ,那么尝试使用getifaddrs()的这段代码:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(ifa->ifa_name,"wlan0")==0)&&(ifa->ifa_addr->sa_family==AF_INET))
{
if (s != 0)
{
printf("getnameinfo() failed: %s
", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf(" Interface : <%s>
",ifa->ifa_name );
printf(" Address : <%s>
", host);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
您可以将wlan0替换为eth0(表示以太网)和lo(表示本地环回)。
所用数据结构的结构和详细解释可在此处找到。
要了解有关 C 中的链表的更多信息,此页面将是一个很好的起点。
解决方案 4:
我的看法:即使在 iOS 上,同样的代码也能正常工作:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
showIP();
}
void showIP()
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if( /*(strcmp(ifa->ifa_name,"wlan0")==0)&&( */ ifa->ifa_addr->sa_family==AF_INET) // )
{
if (s != 0)
{
printf("getnameinfo() failed: %s
", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf(" Interface : <%s>
",ifa->ifa_name );
printf(" Address : <%s>
", host);
}
}
freeifaddrs(ifaddr);
}
@end
我只是删除了针对 wlan0 的测试来查看数据。ps 您可以删除“family”
解决方案 5:
我最近也遇到了同样的问题,这是我编写的代码,它可以正常工作。请确保使用网络接口的名称,与您拥有的名称完全一致(可以是“eth0”或其他)。
必须ifconfig
事先检查命令以获取接口名称并在 C 中使用它。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <linux/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void extract_ipaddress()
{
//create an ifreq struct for passing data in and out of ioctl
struct ifreq my_struct;
//declare and define the variable containing the name of the interface
char *interface_name="enp0s3"; //a very frequent interface name is "eth0";
//the ifreq structure should initially contains the name of the interface to be queried. Which should be copied into the ifr_name field.
//Since this is a fixed length buffer, one should ensure that the name does not cause an overrun
size_t interface_name_len=strlen(interface_name);
if(interface_name_len<sizeof(my_struct.ifr_name))
{
memcpy(my_struct.ifr_name,interface_name,interface_name_len);
my_struct.ifr_name[interface_name_len]=0;
}
else
{
perror("Copy name of interface to ifreq struct");
printf("The name you provided for the interface is too long...
");
}
//provide an open socket descriptor with the address family AF_INET
/* ***************************************************************
* All ioctl call needs a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket file descriptor. This socket must be in the address family that you wish to obtain (AF_INET for IPv4)
* ***************************************************************
*/
int file_descriptor=socket(AF_INET, SOCK_DGRAM,0);
if(file_descriptor==-1)
{
perror("Socket file descriptor");
printf("The construction of the socket file descriptor was unsuccessful.
");
return -1;
}
//invoke ioctl() because the socket file descriptor exists and also the struct 'ifreq' exists
int myioctl_call=ioctl(file_descriptor,SIOCGIFADDR,&my_struct);
if (myioctl_call==-1)
{
perror("ioctl");
printf("Ooops, error when invoking ioctl() system call.
");
close(file_descriptor);
return -1;
}
close(file_descriptor);
/* **********************************************************************
* If this completes without error , then the hardware address of the interface should have been returned in the 'my_struct.ifr_addr' which is types as struct sockaddr_in.
* ***********************************************************************/
//extract the IP Address (IPv4) from the my_struct.ifr_addr which has the type 'ifreq'
/* *** Cast the returned address to a struct 'sockaddr_in' *** */
struct sockaddr_in * ipaddress= (struct sockaddr_in *)&my_struct.ifr_addr;
/* *** Extract the 'sin_addr' field from the data type (struct) to obtain a struct 'in_addr' *** */
printf("IP Address is %s.
", inet_ntoa(ipaddress->sin_addr));
}
解决方案 6:
如果您不介意二进制大小,您可以使用 iproute2 作为库。
iproute2-as-lib
优点:
不需要编写socket层代码。
可以获取有关网络接口的更多甚至更多信息。与 iproute2 工具具有相同的功能。
简单的API接口。
缺点:
iproute2-as-lib 库很大。~500kb。
解决方案 7:
我发现了一个获取 ip 的相当简单的方法,利用 bash 命令:
hostname -I
但是使用“hostname -I”本身会在屏幕上打印结果,我们需要使用“popen()”读取结果并将其保存为字符串,这里是 c 代码:
#include <stdio.h> // popen
#include "ip_common_def.h"
const char * get_ip()
{
// Read out "hostname -I" command output
FILE *fd = popen("hostname -I", "r");
if(fd == NULL) {
fprintf(stderr, "Could not open pipe.
");
return NULL;
}
// Put output into a string (static memory)
static char buffer[IP_BUFFER_LEN];
fgets(buffer, IP_BUFFER_LEN, fd);
// Only keep the first ip.
for (int i = 0; i < IP_BUFFER_LEN; ++i)
{
if (buffer[i] == ' ')
{
buffer[i] = ' ';
break;
}
}
char *ret = malloc(strlen(buffer) + 1);
memcpy(ret, buffer, strlen(buffer));
ret[strlen(buffer)] = ' ';
printf("%s
", ret);
return ret;
}
相关推荐
热门文章
项目管理软件有哪些?
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
热门标签
云禅道AD