linux网络接口,struct ifreq struct ifconf结构
网络相关的ioctl请求的request参数及arg地址必须指向的数据类型如下表所示:
接口 |
SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFBRDADDR SIOCGIFBRDADDR SIOCSIFNETMASK SIOCGIFNETMASK |
获取所有接口列表 设置接口地址 获取接口地址 设置广播地址 获取广播地址 设置子网掩码 获取子网掩码 |
Struct ifconf Struct ifreq Struct ifreq Struct ifreq Struct ifreq Struct ifreq Struct ifreq |
Ifreq结构用来配置ip地址,激活接口,配置MTU。在Linux系统中获取IP地址通常都是通过ifconfig命令来实现的,然而ifconfig命令实际是通过ioctl接口与内核通信,ifconfig命令首先打开一个socket,然后调用ioctl将request传递到内核,从而获取request请求数据。处理网络接口的许多程序沿用的初始步骤之一就是从内核获取配置在系统中的所有接口。
struct ifreq data; fd = socket(AF_NET,SOCK_DGRAM,0); ioctl(fd,SIOCGIFADDR,&data);
struct ifconf结构体
struct ifconf{ lint ifc_len; union{ caddr_t ifcu_buf struct ifreq *ifcu_req; }ifc_ifcu } #define ifc_buf ifc_ifcu.ifcu_buf #define ifc_req ifc_ifcu.ifcu_req
struct ifreq接口
struct ifreq{ char ifr_name[IFNAMSIZ]; union{ struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short ifru_flags; int ifru_metric; caddr_t ifru_data; }ifr_ifru; }; #define ifr_addr ifr_ifru.ifru_addr #define ifr_broadaddr ifr_ifru.ifru_broadadd #define ifr_hwaddr ifr_ifru_hwaddr
对于ifconf中ifc_buf,其实就是N个ifc_req,从上面的结构体中可以看出来,通过下面两幅图可以更加明显。
#include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netdb.h> #include <string.h> #include <fcntl.h> #include <string.h> #include <errno.h> typedef uint32_t uint32; #define MAX_IF 10 int main() { struct ifreq ifVec[MAX_IF]; //保存所有借口 int sock = -1; if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) fprintf(stderr, "Error:%d, cannot open RAM;\n"); // get if verctor struct ifconf ioIfConf; ioIfConf.ifc_buf = (void *)ifVec; ioIfConf.ifc_len = sizeof(ifVec); printf("Len:%d\n", ioIfConf.ifc_len); if(ioctl(sock, SIOCGIFCONF, &ioIfConf) < 0) //获取所有网络接口信息 fprintf(stderr, "Error:%d ioctl IFCONF\n"); printf("Len:%d\n", ioIfConf.ifc_len); //和前面到len对比,发现ioctl修改里len到大小 //循环打印每个网络接口到信息 { struct ifreq *ifPt; struct ifreq *ifEndPt; ifPt = ifVec; ifEndPt = (void *)((char *)ifVec + ioIfConf.ifc_len); for(ifPt = ifVec; ifPt < ifEndPt; ifPt++) { struct ifreq ifReq; if(ifPt->ifr_addr.sa_family != AF_INET) { continue; } // Temp keepers of interface params ... uint32 u32_addr, u32_mask; /* 打印ip地址地址 */ char ipDotBuf[16], subnetDotBuf[16], maskDotBuf[16]; //保存点分十进制到ip地址 u32_addr = ((struct sockaddr_in *)&ifPt->ifr_addr)->sin_addr.s_addr; inet_ntop(AF_INET, &u32_addr, ipDotBuf, (socklen_t)sizeof(ipDotBuf)); printf("IP Address: %s\n", ipDotBuf); /* 打印地址掩码 */ bzero(&ifReq, sizeof(struct ifreq)); memcpy(ifReq.ifr_name, ifPt->ifr_name, sizeof(ifReq.ifr_name)); if(ioctl(sock, SIOCGIFNETMASK, &ifReq) < 0) { fprintf(stderr, "Error: %d, cannot get mask\n", errno); } else { u32_mask = ((struct sockaddr_in *)&ifReq.ifr_addr)->sin_addr.s_addr; inet_ntop(AF_INET, &u32_mask, maskDotBuf, (socklen_t)sizeof(maskDotBuf)); printf("Mask: %s\n", maskDotBuf); } /* 打印MTU */ bzero(&ifReq, sizeof(struct ifreq)); memcpy(ifReq.ifr_name, ifPt->ifr_name, sizeof(ifReq.ifr_name)); if(ioctl(sock, SIOCGIFMTU, &ifReq) < 0) { fprintf(stderr, "Error: %d, cannot get MTU\n", errno); } else { printf("SIOCGIFMTU: %d\n", ifReq.ifr_mtu); } /* 其他信息的打印方式与掩码和MTU相同 */ } } }
无欲速,无见小利。欲速,则不达;见小利,则大事不成。