环境配置
上一篇文章主要讲了AIX系统下的单网卡多IP的IP的配置以及C语言获取的方法。相比AIX,Linux下配置就方便得多。
首先找到我们需要配置的网卡名,比如p2p2
, 进入到/etc/sysconfig/network-scripts/
目录,找到ifcgf-p2p2
文件,打开是这个样子的:
TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=static DEFROUTE=no IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=p2p2 UUID=0a69226b-6051-4cb4-a1d3-17f37896275a DEVICE=p2p2 ONBOOT=no GATEWAY=192.168.11.1 IPADDR=192.168.11.111 NETMASK=255.255.255.0 DNS=114.114.114.114
我们直接在里面增加需要添加的IP,如下所示:
TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=static DEFROUTE=no IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=p2p2 UUID=0a69226b-6051-4cb4-a1d3-17f37896275a DEVICE=p2p2 ONBOOT=no 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
。
保存后将网卡重新上线一下:
[root@ck10 chenyc]#ifdown p2p2 [root@ck10 chenyc]#ifup p2p2
完成后,从ifcofig
是看不出来的:
[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<link> 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
命令可以看到已经生效:
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实现方法有很多,我这里演示两种实现方法。
方法一
#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\n", ifa->ifa_name, ip); } } freeifaddrs(ifaddr); exit(EXIT_SUCCESS); }
第一种方法主要是利用getifaddrs
函数获取到所有的网卡信息,这些信息会返回到一个 struct ifaddrs
结构体中,该结构体本身是一个单向链表,结构如下所示:
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 */ };
其中,ifa_next
存储的是下一条网卡信息的地址,ifa_name
存储的是网卡名,ifa_addr
存储的就是IP
地址。
不过这个函数会获取到一些冗余的信息,这些信息并不是我们所需要的,上面代码运行结果如下所示:
[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
。
方法二
#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\n", inet_ntoa(sin->sin_addr)); } ifr++; } close(sock_fd); return -1; }
这段代码的逻辑就好理解得多。直接调用ioctl
接口,先用SIOCGIFCONF
获取到所有的网卡,然后再用SIOCGIFFLAGS
依次拿到各个网卡的信息即可。这样子取出来的数据就是我们需要的结果。
上面代码运行结果如下:
[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服务器开发/高级架构师