C语言获取Linux单网卡的多IP地址_嵌入式linux多个ip

随笔4个月前发布 小晶
31 0 0

GATEWAY=192.168.11.1
IPADDR=192.168.11.111
NETMASK=255.255.255.0
DNS=114.114.114.114
IPADDR2=192.168.11.11
GATEWAY2=192.168.11.1
NETMASK2=255.255.255.0
DNS2=114.114.114.114
IPADDR3=192.168.11.12
GATEWAY3=192.168.11.1
NETMASK3=255.255.255.0
DNS3=114.114.114.114


如上图,我们增加了两个IP, 一个为`192.168.11.11`,一个为`192.168.11.12`。  
 保存后将网卡重新上线一下:




123456

[root@ck10 chenyc]#ifdown p2p2
[root@ck10 chenyc]#ifup p2p2


完成后,从`ifcofig`是看不出来的:




12345

[root@ck10 chenyc]# ifconfig p2p2
p2p2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.11.111 netmask 255.255.255.0 broadcast 192.168.11.255
inet6 fe80::cd7f:92f2:deb5:fb14 prefixlen 64 scopeid 0x20
ether 90:e2:ba:8f:06:41 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 232 bytes 47704 (46.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0


但是用`ip a`命令可以看到已经生效:




12345

7: p2p2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 90:e2:ba:8f:06:41 brd ff:ff:ff:ff:ff:ff
inet 192.168.11.111/24 brd 192.168.11.255 scope global noprefixroute p2p2
valid_lft forever preferred_lft forever
inet 192.168.11.11/24 brd 192.168.11.255 scope global secondary noprefixroute p2p2
valid_lft forever preferred_lft forever
inet 192.168.11.12/24 brd 192.168.11.255 scope global secondary noprefixroute p2p2
valid_lft forever preferred_lft forever
inet6 fe80::cd7f:92f2:deb5:fb14/64 scope link noprefixroute
valid_lft forever preferred_lft forever


## C代码实现


Linux 下获取单网卡的多IP实现方法有很多,我这里演示两种实现方法。


### 方法一




1234567891011

#include <stdio.h>
#include <stdlib.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/if.h>
#include<string.h>
int main(int argc, char **argv) {
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1) {
perror(“getifaddrs”);
exit(EXIT_FAILURE);
}

for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
    if (ifa->ifa_addr == NULL) {
        continue;
    }
    if (strcmp(ifa->ifa_name, "p2p2") == 0 ){
            char ip[64] = {0};
            struct sockaddr\_in *sock = ( struct sockaddr\_in*)ifa->ifa_addr;
            inet\_ntop(AF_INET,&sock->sin_addr, ip, sizeof(ip));
            printf("name: %s, ip: %s
", ifa->ifa_name, ip);
    }
}

freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);

1234567891011121314

}


第一种方法主要是利用`getifaddrs`函数获取到所有的网卡信息,这些信息会返回到一个 `struct ifaddrs`结构体中,该结构体本身是一个单向链表,结构如下所示:




12345
        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 */
       };


12345678910111213141516

其中,`ifa_next`存储的是下一条网卡信息的地址,`ifa_name`存储的是网卡名,`ifa_addr`存储的就是`IP`地址。  
 不过这个函数会获取到一些冗余的信息,这些信息并不是我们所需要的,上面代码运行结果如下所示:




123456

[root@ck10 chenyc]# ./1
name: p2p2, ip: 7.0.0.0
name: p2p2, ip: 192.168.11.111
name: p2p2, ip: 192.168.11.11
name: p2p2, ip: 192.168.11.12
name: p2p2, ip: 0.0.0.0


多了一个`7.0.0.0`和`0.0.0.0`。


### 方法二




12345678

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include<stdio.h>
#define BUF_SIZE 1024

int main()
{
int sock_fd;
struct ifconf conf;
struct ifreq *ifr;
char buff[BUF_SIZE] = {0};
int num;
int i;

sock_fd = socket(PF_INET, SOCK_DGRAM, 0);
if ( sock_fd < 0 )     
    return -1;
conf.ifc_len = BUF_SIZE;
conf.ifc_buf = buff;

if ( ioctl(sock_fd, SIOCGIFCONF, &conf) < 0 )
{
    close(sock_fd);
    return -1;
}

num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;

for(i = 0; i < num; i++)
{
    struct sockaddr\_in *sin = (struct sockaddr\_in *)(&ifr->ifr_addr);
    if ( ioctl(sock_fd, SIOCGIFFLAGS, ifr) < 0 )
    {
            close(sock_fd);
            return -1;
    }
    if ( (ifr->ifr_flags & IFF_UP) && strcmp("p2p2",ifr->ifr_name) == 0 )
    {
         printf("ip: %s
", inet\_ntoa(sin->sin_addr));
    }
    ifr++;
}
close(sock_fd);
return -1;


12345678910111213141516171819202122232425262728293031

}


这段代码的逻辑就好理解得多。直接调用`ioctl`接口,先用`SIOCGIFCONF`获取到所有的网卡,然后再用`SIOCGIFFLAGS`依次拿到各个网卡的信息即可。这样子取出来的数据就是我们需要的结果。  
 上面代码运行结果如下:




123456

[root@ck10 chenyc]# ./2
ip: 192.168.11.111
ip: 192.168.11.11
ip: 192.168.11.12




---


推荐一个零声学院免费教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,  
 fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,  
 TCP/IP,协程,DPDK等技术内容,点击立即学习: [C/C++Linux服务器开发/高级架构师]( )





12345678910111213
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...