CNet 网络配置工具类详解平台仅支持Linux大量使用ioctl系统调用一、概述CNet是一个纯静态方法的网络配置工具类封装了 Linux 下常用的网络操作功能类别涵盖内容IP 地址读取/设置本机 IP、子网掩码网关读取/添加/删除/设置默认网关DNS读取/写入/etc/resolv.confMAC 地址读取本机 MAC、生成随机 MAC网卡状态网线插入检测、网卡使能/禁用、接口是否存在路由 metric设置网卡路由优先级Socket 绑定将套接字绑定到指定网卡全部方法都是static无需实例化即可调用。二、头文件与依赖externC{#includestdio.h#includestring.h#includearpa/inet.h// inet_ntoa(), inet_addr()#includesys/ioctl.h// ioctl 系统调用#includenet/if.h// ifreq, IFNAMSIZ#includeunistd.h#includelinux/if.h#includelinux/ethtool.h// ETHTOOL_GLINK 网线检测#includelinux/rtnetlink.h// 路由#includenet/route.h// rtentry 路由结构#includesys/time.h#includedirent.h};核心武器是ioctl——Linux 下操作网络接口的全能接口。三、IP 地址操作3.1 整数 ↔ 字符串互转// 整数 IP网络字节序 → 字符串 192.168.1.100char*IpU32ToStr(uint32_tu32_ip);// 字符串 IP → 整数网络字节序unsignedintIpStrToU32(constchar*sz_ip);内部其实就两层皮// IpU32ToStr 内部returninet_ntoa(*(structin_addr*)u32_ip);// IpStrToU32 内部returninet_addr(sz_ip);⚠️inet_addr()在 IP 为0时返回INADDR_NONE但代码未做校验实际使用有坑。3.2 读取本机 IPboolGetLocalIp(constchar*interface_name,char*sz_ip,uint32_tu32_ip);实现套路后文类似方法都这个套路intsock_fdsocket(AF_INET,SOCK_DGRAM,0);// 创建套接字strncpy(stIfreq.ifr_name,interface_name,IFNAME_SIZE);ioctl(sock_fd,SIOCGIFADDR,stIfreq);// 发给内核问 IP// 取出结果转换关闭套接字SIOCGIFADDR Socket I/O Control 获取接口地址。3.3 设置本机 IPboolSetLocalIp(constchar*interface_name,constchar*sz_ip);boolSetLocalIp(constchar*interface_name,uint32_tu32_ip);socksocket(AF_INET,SOCK_DGRAM,0);// 注意是 DGRAM不是 STREAMstrncpy(ifr.ifr_name,interface_name,IFNAMSIZ);si.sin_familyPF_INET;si.sin_addr.s_addru32_ip;memcpy(ifr.ifr_addr,si,sizeof(structsockaddr_in));ioctl(sock,SIOCSIFADDR,ifr);// SIOCS SetSIOCSIFADDR Socket I/O Control Set Interface Address。3.4 子网掩码读取/设置boolGetNetMask(constchar*interface_name,char*sz_mask);boolGetNetMask(constchar*interface_name,uint32_tmask);boolSetNetMask(constchar*interface_name,constchar*sz_mask);boolSetNetMask(constchar*interface_name,uint32_tmask);底层用SIOCGIFNETMASK/SIOCSIFNETMASKioctl。四、网关路由操作这是最复杂的部分涉及/proc/net/route文件解析。4.1 核心数据结构structroute_info{u_int dstAddr;u_int srcAddr;u_int gateWay;charifName[IF_NAMESIZE];};4.2 读取网关boolGetLocalGateWay(constchar*interface_name,char*sz_gw);boolGetLocalGateWay(constchar*interface_name,uint32_tgw);实现打开/proc/net/route逐行解析// /proc/net/route 格式示例// Iface Destination Gateway Flags RefCnt Use Metric Mask ...// eth0 00000000 0A00020A 0003 ... ... 100 0000F0F8FILE*fpfopen(PROCNET_ROUTE_PATH,r);// /proc/net/routefgets(buff,130,fp);// 跳过表头while(fgets(buff,130,fp)!NULL){sscanf(buf,%15s\t%08lX\t%08lX\t%8X\t,iface,dest,gate,iflags);if(!strcmp(iface,interface_name)){if(iflags(RTF_UP|RTF_GATEWAY))(RTF_UP|RTF_GATEWAY)){gwgate;// gate 是 16 进制整数returntrue;}}}4.3 设置网关先清后加boolSetLocalGateWay(constchar*interface_name,constchar*sz_gw);boolSetLocalGateWay(constchar*interface_name,uint32_tgw);流程CleanGateWay()→AddLocalGateWay()boolSetLocalGateWay(constchar*interface_name,uint32_tgw){CleanGateWay(interface_name);// 先删所有旧路由returnAddLocalGateWay(interface_name,gw);// 再加新路由}4.4 添加/删除网关staticboolAddLocalGateWay(constchar*interface_name,uint32_tgw);staticboolDelLocalGateWay(constchar*interface_name,uint32_tgw);底层通过SIOCADDRTAdd Route和SIOCDELRTDelete Routeioctl 实现structrtentryrt;memset(rt,0,sizeof(structrtentry));rt.rt_flags(RTF_UP|RTF_GATEWAY);// 标识为网关路由rt.rt_dst.sa_familyPF_INET;rt.rt_genmask.sa_familyPF_INET;sa.sin_addr.s_addrgw;memcpy(rt.rt_gateway,sa,sizeof(structsockaddr));intskfdsocket(AF_INET,SOCK_DGRAM,0);ioctl(skfd,SIOCADDRT,rt);// 写入内核路由表close(skfd);五、DNS 服务器操作直接读写/etc/resolv.confboolSetDNSServerIP(constchar*first_dns,constchar*second_dns);boolGetDNSServerIP(char*first_dns,char*second_dns);写操作FILE*fpfopen(RESOLV_CONF,w);// /etc/resolv.confsnprintf(buf,sizeof(buf)-1,nameserver %s\nnameserver %s\n,first_dns,second_dns);fwrite(buf,1,strlen(buf),fp);fflush(fp);fclose(fp);读操作用LastPos()找到每行nameserver后面的空格位置提取 IP。六、MAC 地址操作6.1 读取本机 MACboolGetLocalMac(constchar*interface_name,char*sz_mac);通过SIOCGIFHWADDRioctl 获取strncpy(ifreq.ifr_name,interface_name,...);ioctl(sockfd,SIOCGIFHWADDR,ifreq);// 获取硬件地址memcpy(mac_data,ifreq.ifr_hwaddr.sa_data,6);MacNumToStr(mac_data,sz_mac);// 格式化成 XX:XX:XX:XX:XX:XX6.2 随机 MAC 生成boolGetRandomMacAddr(char*sz_mac);生成 6 字节随机数但会过滤掉全零和多播地址do{for(i0;i6;i)mac[i]rand()0xFF;}while(!IsValidEtherAddr((char*)mac));// 校验通过为止七、网卡状态检测7.1 网线是否插入boolIsCablePluggedIn(constchar*interface_name);使用ethtool接口structethtool_valueeth_data;eth_data.cmdETHTOOL_GLINK;// 查询链路状态eth_data.data0;ifr.ifr_data(char*)eth_data;ioctl(sock,SIOCETHTOOL,ifr);// 发给 ethtool 驱动// eth_data.data 0 表示网线插着7.2 网卡是否启用boolGetNetworkEnableStatus(constchar*interface_name,boolenable);boolSetNetworkEnableStatus(constchar*interface_name,boolenable);通过SIOCGIFFLAGSGet和SIOCSIFFLAGSSet操作ifr_flagsioctl(sock,SIOCGIFFLAGS,ifr);enable(ifr.ifr_flagsIFF_UP)!0;// IFF_UP 表示已启用// 设置禁用ifr.ifr_flags~IFF_UP;ioctl(sock,SIOCSIFFLAGS,ifr);// 设置启用ifr.ifr_flags|IFF_UP|IFF_RUNNING;7.3 网卡接口是否存在boolIsNetworkInterfaceExist(constchar*interface_name);boolGetAllNetworkInterface(std::vectorstd::stringinterface_name);遍历/sys/class/net目录DIR*diropendir(/sys/class/net);structdirent*entry;while((entryreaddir(dir))!NULL){if(entry-d_typeDT_LNK!strcmp(entry-d_name,interface_name)){existtrue;}}closedir(dir);八、Socket 绑定到网卡boolSockBindInterface(constchar*interface_name,intsock_fd);使用SOL_SOCKET/SO_BINDTODEVICE选项strncpy(interface.ifr_ifrn.ifrn_name,interface_name,...);setsockopt(sock_fd,SOL_SOCKET,SO_BINDTODEVICE,(char*)interface_name,sizeof(interface));这样该 socket 收发的数据包都走指定网卡。九、路由优先级MetricboolSetRouteMetric(constchar*interface_name,uint32_tmetric);ifr.ifr_metricmetric;// 0-255值越大优先级越低ioctl(sockfd,SIOCSIFMETRIC,ifr);十、总结技术亮点说明ioctl系统调用贯穿整个模块操作网络接口的金钥匙/proc/net/route读取内核路由表手动解析文本/etc/resolv.conf直接读写 DNS 配置/sys/class/net遍历网卡接口ethtoolioctl查询网线物理连接状态路由表操作SIOCADDRT/SIOCDELRT动态增删路由整体是一个贴近 Linux 底层实现的网络配置工具设计思路务实不依赖第三方库适合嵌入式 Linux 场景。