From a9ca7f7ca6fdda8ac981af34b3917a42e42614d5 Mon Sep 17 00:00:00 2001 From: gaoyutao Date: Tue, 16 Dec 2025 20:58:53 +0800 Subject: [PATCH] =?UTF-8?q?agent=E7=BD=91=E5=8D=A1=E6=8E=A2=E6=B5=8B?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E4=BF=AE=E6=94=B9=E3=80=82=20=E7=BD=91?= =?UTF-8?q?=E5=8D=A1=E6=B5=81=E9=87=8F=E6=8E=A2=E6=B5=8B=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=B2=A1=E9=85=8DIP=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scheduler/service/AppInitializer.java | 4 +- .../scheduler/service/BusinessTasks.java | 10 +- .../client/service/impl/NetServiceImpl.java | 344 +++++++++++++----- .../tongran/agent/client/utils/AgentUtil.java | 10 + 4 files changed, 280 insertions(+), 88 deletions(-) diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java b/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java index 0628a32..0de2717 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java @@ -10,6 +10,7 @@ import com.tongran.agent.client.netty.model.Message; import com.tongran.agent.client.service.AgentService; import com.tongran.agent.client.utils.AgentUtil; import com.tongran.agent.client.utils.AssertLog; +import com.tongran.agent.client.utils.NetworkInterfaceUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Lazy; @@ -108,7 +109,8 @@ public class AppInitializer implements CommandLineRunner { } long timestamps = System.currentTimeMillis(); timestamps = Math.round(timestamps / 1000.0); - List infos = AgentUtil.collectNetworkInfo(); +// List infos = AgentUtil.collectNetworkInfo(); + List infos = NetworkInterfaceUtil.collectNetworkInfo(); JSONObject objects = new JSONObject(); objects.put("clientId", GlobalConfig.CLIENT_ID); objects.put("sn", GlobalConfig.DEVICE_SN); diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java index a6a4084..22ea99b 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java @@ -15,6 +15,7 @@ import com.tongran.agent.client.netty.model.Message; import com.tongran.agent.client.service.*; import com.tongran.agent.client.utils.AgentUtil; import com.tongran.agent.client.utils.AssertLog; +import com.tongran.agent.client.utils.NetworkInterfaceUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; @@ -788,7 +789,8 @@ public class BusinessTasks { if(StringUtils.isBlank(GlobalConfig.DEVICE_SN)){ GlobalConfig.DEVICE_SN = AgentUtil.getDeviceSN(); } - List infos = AgentUtil.collectNetworkInfo(); +// List infos = AgentUtil.collectNetworkInfo(); + List infos = NetworkInterfaceUtil.collectNetworkInfo(); JSONObject object = new JSONObject(); object.put("clientId", GlobalConfig.CLIENT_ID); object.put("sn", GlobalConfig.DEVICE_SN); @@ -862,7 +864,8 @@ public class BusinessTasks { } long timestamps = System.currentTimeMillis(); timestamps = Math.round(timestamps / 1000.0); - List infos = AgentUtil.collectNetworkInfo(); +// List infos = AgentUtil.collectNetworkInfo(); + List infos = NetworkInterfaceUtil.collectNetworkInfo(); JSONObject objects = new JSONObject(); objects.put("clientId", GlobalConfig.CLIENT_ID); objects.put("sn", GlobalConfig.DEVICE_SN); @@ -899,7 +902,8 @@ public class BusinessTasks { timestamps = Math.round(timestamps / 1000.0); List infos = null; try { - infos = AgentUtil.collectNetworkInfo(); +// infos = AgentUtil.collectNetworkInfo(); + infos = NetworkInterfaceUtil.collectNetworkInfo(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java index 3d8ffc5..70b7cd7 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java @@ -12,11 +12,17 @@ import oshi.util.FormatUtil; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.nio.file.*; import java.util.*; +import java.util.stream.Collectors; @Service public class NetServiceImpl implements NetService { + // 用于保存总流量统计 + private Map totalBytesRecvMap = new HashMap<>(); + private Map totalBytesSentMap = new HashMap<>(); + @Override public List netList(long timestamp) { List list = new ArrayList<>(); @@ -25,114 +31,281 @@ public class NetServiceImpl implements NetService { HardwareAbstractionLayer hal = si.getHardware(); List networkIFs = hal.getNetworkIFs(); + // 获取系统所有物理网卡 + Set allPhysicalInterfaces = getAllPhysicalInterfaces(); + + System.out.println("系统所有物理网卡: " + allPhysicalInterfaces); + System.out.println("OSHI识别的网卡: " + networkIFs.stream().map(NetworkIF::getName).collect(Collectors.toList())); + + // 创建网卡名称到NetworkIF对象的映射 + Map networkIFMap = new HashMap<>(); + for (NetworkIF net : networkIFs) { + networkIFMap.put(net.getName(), net); + } + System.out.println("========================================================="); System.out.println("===== 网卡流量统计(基于iptables统计) ====="); - // 第一次采样 - 获取基本数据 + // 第一次采样 for (NetworkIF net : networkIFs) { net.updateAttributes(); } - // 等待1秒进行第二次采样 + // 等待1秒(仅用于获取瞬时流量速率,实际计算总流量时不需要) Thread.sleep(1000); // 获取iptables统计信息 Map> iptablesStats = getIptablesStatistics(); - // 第二次采样并计算流量 - for (NetworkIF net : networkIFs) { - net.updateAttributes(); + // 处理所有物理网卡 + for (String interfaceName : allPhysicalInterfaces) { + NetworkIF net = networkIFMap.get(interfaceName); + NetVO netVO = null; - String interfaceName = net.getName(); - boolean isBusinessInterface = GlobalConfig.NETNAME.contains(interfaceName); - String[] ipv6Arr = net.getIPv6addr(); - String publicIpv6 = ""; - for (String ipv6 : ipv6Arr) { - if(AgentUtil.isPublicIPv6(ipv6)){ - publicIpv6 = ipv6; - break; - } - } - - System.out.println("接口名称: " + interfaceName + "(" + net.getDisplayName() + ")"); - System.out.println("MAC地址: " + net.getMacaddr()); - System.out.println("运行状态: " + (net.isConnectorPresent() ? "已连接" : "未连接")); - System.out.println("接口类型: " + AgentUtil.getInterfaceType(net)); - System.out.println("IPv4地址: " + String.join(", ", net.getIPv4addr())); - System.out.println("公网IPv6地址: " + publicIpv6); - System.out.println("业务网卡: " + (isBusinessInterface ? "是" : "否")); - - // 获取总流量 - long totalBytesRecv = net.getBytesRecv(); - long totalBytesSent = net.getBytesSent(); - - Long ipv4BytesRecv = null, ipv4BytesSent = null; - Long ipv6BytesRecv = null, ipv6BytesSent = null; - - if (isBusinessInterface) { - // 业务网卡:使用iptables统计区分IPv4/IPv6流量 - Map interfaceStats = iptablesStats.get(interfaceName); - if (interfaceStats != null) { - ipv4BytesRecv = interfaceStats.get("ipv4Recv"); - ipv4BytesSent = interfaceStats.get("ipv4Sent"); - ipv6BytesRecv = interfaceStats.get("ipv6Recv"); - ipv6BytesSent = interfaceStats.get("ipv6Sent"); - - System.out.println("iptables统计 - IPv4接收: " + (ipv4BytesRecv != null ? FormatUtil.formatBytes(ipv4BytesRecv) : "null") + - ", IPv4发送: " + (ipv4BytesSent != null ? FormatUtil.formatBytes(ipv4BytesSent) : "null") + - ", IPv6接收: " + (ipv6BytesRecv != null ? FormatUtil.formatBytes(ipv6BytesRecv) : "null") + - ", IPv6发送: " + (ipv6BytesSent != null ? FormatUtil.formatBytes(ipv6BytesSent) : "null")); - } else { - System.out.println("警告: 未找到网卡 " + interfaceName + " 的iptables统计信息"); - } + if (net != null) { + // OSHI能识别到的网卡 + netVO = processNetworkIF(net, iptablesStats, timestamp); } else { - // 非业务网卡:IPv4/IPv6流量设为null - System.out.println("非业务网卡,IPv4/IPv6流量统计为null"); + // OSHI未识别到的网卡(无IP配置的网卡) + netVO = processMissingNetworkIF(interfaceName, timestamp); } - System.out.println("总接收流量: " + FormatUtil.formatBytes(totalBytesRecv)); - System.out.println("总发送流量: " + FormatUtil.formatBytes(totalBytesSent)); - System.out.println("IPv4接收流量: " + (ipv4BytesRecv != null ? FormatUtil.formatBytes(ipv4BytesRecv) : "null")); - System.out.println("IPv4发送流量: " + (ipv4BytesSent != null ? FormatUtil.formatBytes(ipv4BytesSent) : "null")); - System.out.println("IPv6接收流量: " + (ipv6BytesRecv != null ? FormatUtil.formatBytes(ipv6BytesRecv) : "null")); - System.out.println("IPv6发送流量: " + (ipv6BytesSent != null ? FormatUtil.formatBytes(ipv6BytesSent) : "null")); - System.out.println("入站丢包: " + net.getInDrops()); - System.out.println("出站丢包: " + net.getCollisions()); - - NetVO netVO = NetVO.builder() - .name(net.getName() + "(" + net.getDisplayName() + ")") - .mac(net.getMacaddr()) - .status(net.isConnectorPresent() ? "已连接" : "未连接") - .type(AgentUtil.getInterfaceType(net)) - .ipV4(String.join(", ", net.getIPv4addr())) - .ipV6(publicIpv6) - .inDropped(net.getInDrops()) - .outDropped(net.getCollisions()) - .inSpeed(totalBytesRecv) - .outSpeed(totalBytesSent) - .ipv4InSpeed(ipv4BytesRecv) - .ipv4OutSpeed(ipv4BytesSent) - .ipv6InSpeed(ipv6BytesRecv) - .ipv6OutSpeed(ipv6BytesSent) - .timestamp(timestamp) - .build(); - - // 设置协商速度和工作模式 - Map ethtoolMap = getNetworkMode(net.getName()); - if (ethtoolMap != null && !ethtoolMap.isEmpty()) { - netVO.setSpeed(ethtoolMap.get("speed")); - netVO.setDuplex(ethtoolMap.get("duplex")); + if (netVO != null) { + list.add(netVO); } - - list.add(netVO); - System.out.println("-----------------------------------------"); } + } catch (Exception e) { e.printStackTrace(); } return list; } + /** + * 获取系统所有物理网卡(包括无IP的) + */ + private Set getAllPhysicalInterfaces() { + Set interfaces = new HashSet<>(); + Path netPath = Paths.get("/sys/class/net"); + + try (DirectoryStream stream = Files.newDirectoryStream(netPath)) { + for (Path interfacePath : stream) { + String interfaceName = interfacePath.getFileName().toString(); + + // 跳过虚拟网卡(可选,根据需求调整) + if (interfaceName.startsWith("lo")) { + continue; + } + + interfaces.add(interfaceName); + } + } catch (Exception e) { + System.err.println("读取网卡列表失败: " + e.getMessage()); + } + + return interfaces; + } + + /** + * 从/sys读取网卡统计信息 + */ + private Long getBytesFromSys(String interfaceName, String statFile) { + try { + Path statPath = Paths.get("/sys/class/net", interfaceName, "statistics", statFile); + if (Files.exists(statPath)) { + String content = Files.readAllLines(statPath).get(0).trim(); + return Long.parseLong(content); + } + } catch (Exception e) { + System.err.println("读取网卡 " + interfaceName + " 的 " + statFile + " 失败: " + e.getMessage()); + } + return 0L; + } + + /** + * 处理OSHI能识别到的网卡 + */ + private NetVO processNetworkIF(NetworkIF net, Map> iptablesStats, long timestamp) { + try { + net.updateAttributes(); + + String interfaceName = net.getName(); + boolean isBusinessInterface = GlobalConfig.NETNAME.contains(interfaceName); + String[] ipv6Arr = net.getIPv6addr(); + String publicIpv6 = ""; + for (String ipv6 : ipv6Arr) { + if(AgentUtil.isPublicIPv6(ipv6)){ + publicIpv6 = ipv6; + break; + } + } + + System.out.println("接口名称: " + interfaceName + "(" + net.getDisplayName() + ")"); + System.out.println("MAC地址: " + net.getMacaddr()); + System.out.println("运行状态: " + (net.isConnectorPresent() ? "已连接" : "未连接")); + System.out.println("接口类型: " + AgentUtil.getInterfaceType(net)); + System.out.println("IPv4地址: " + String.join(", ", net.getIPv4addr())); + System.out.println("公网IPv6地址: " + publicIpv6); + System.out.println("业务网卡: " + (isBusinessInterface ? "是" : "否")); + + // 从OSHI获取总流量 + long totalBytesRecv = net.getBytesRecv(); + long totalBytesSent = net.getBytesSent(); + + Long ipv4BytesRecv = null, ipv4BytesSent = null; + Long ipv6BytesRecv = null, ipv6BytesSent = null; + + if (isBusinessInterface) { + Map interfaceStats = iptablesStats.get(interfaceName); + if (interfaceStats != null) { + ipv4BytesRecv = interfaceStats.get("ipv4Recv"); + ipv4BytesSent = interfaceStats.get("ipv4Sent"); + ipv6BytesRecv = interfaceStats.get("ipv6Recv"); + ipv6BytesSent = interfaceStats.get("ipv6Sent"); + } + } + + System.out.println("总接收流量: " + FormatUtil.formatBytes(totalBytesRecv)); + System.out.println("总发送流量: " + FormatUtil.formatBytes(totalBytesSent)); + System.out.println("IPv4接收流量: " + (ipv4BytesRecv != null ? FormatUtil.formatBytes(ipv4BytesRecv) : "null")); + System.out.println("IPv4发送流量: " + (ipv4BytesSent != null ? FormatUtil.formatBytes(ipv4BytesSent) : "null")); + System.out.println("IPv6接收流量: " + (ipv6BytesRecv != null ? FormatUtil.formatBytes(ipv6BytesRecv) : "null")); + System.out.println("IPv6发送流量: " + (ipv6BytesSent != null ? FormatUtil.formatBytes(ipv6BytesSent) : "null")); + System.out.println("入站丢包: " + net.getInDrops()); + System.out.println("出站丢包: " + net.getCollisions()); + + NetVO netVO = NetVO.builder() + .name(net.getName() + "(" + net.getDisplayName() + ")") + .mac(net.getMacaddr()) + .status(net.isConnectorPresent() ? "已连接" : "未连接") + .type(AgentUtil.getInterfaceType(net)) + .ipV4(String.join(", ", net.getIPv4addr())) + .ipV6(publicIpv6) + .inDropped(net.getInDrops()) + .outDropped(net.getCollisions()) + .inSpeed(totalBytesRecv) // 总接收流量 + .outSpeed(totalBytesSent) // 总发送流量 + .ipv4InSpeed(ipv4BytesRecv) + .ipv4OutSpeed(ipv4BytesSent) + .ipv6InSpeed(ipv6BytesRecv) + .ipv6OutSpeed(ipv6BytesSent) + .timestamp(timestamp) + .build(); + + // 设置协商速度和工作模式 + Map ethtoolMap = getNetworkMode(net.getName()); + if (ethtoolMap != null && !ethtoolMap.isEmpty()) { + netVO.setSpeed(ethtoolMap.get("speed")); + netVO.setDuplex(ethtoolMap.get("duplex")); + } + + System.out.println("-----------------------------------------"); + return netVO; + + } catch (Exception e) { + System.err.println("处理网卡 " + net.getName() + " 失败: " + e.getMessage()); + return null; + } + } + + /** + * 处理OSHI未识别的网卡(无IP配置的网卡) + */ + private NetVO processMissingNetworkIF(String interfaceName, long timestamp) { + System.out.println("接口名称: " + interfaceName + "(无IP配置)"); + + try { + // 获取MAC地址 + String macAddr = getMacAddress(interfaceName); + System.out.println("MAC地址: " + (macAddr != null ? macAddr : "未知")); + + // 获取网卡状态 + String status = getInterfaceStatus(interfaceName); + System.out.println("运行状态: " + status); + + // 从/sys获取总流量统计 + Long totalBytesRecv = getBytesFromSys(interfaceName, "rx_bytes"); + Long totalBytesSent = getBytesFromSys(interfaceName, "tx_bytes"); + + // 获取丢包数 + Long inDropped = getBytesFromSys(interfaceName, "rx_dropped"); + Long outDropped = getBytesFromSys(interfaceName, "tx_dropped"); + + System.out.println("总接收流量: " + FormatUtil.formatBytes(totalBytesRecv)); + System.out.println("总发送流量: " + FormatUtil.formatBytes(totalBytesSent)); + System.out.println("入站丢包: " + inDropped); + System.out.println("出站丢包: " + outDropped); + + // 获取协商速度和工作模式 + Map ethtoolMap = getNetworkMode(interfaceName); + String speed = null; + String duplex = null; + if (ethtoolMap != null && !ethtoolMap.isEmpty()) { + speed = ethtoolMap.get("speed"); + duplex = ethtoolMap.get("duplex"); + } + + NetVO netVO = NetVO.builder() + .name(interfaceName + "(无IP配置)") + .mac(macAddr != null ? macAddr : "00:00:00:00:00:00") + .status(status) + .type("Ethernet") + .ipV4("") + .ipV6("") + .inDropped(inDropped) + .outDropped(outDropped) + .inSpeed(totalBytesRecv) // 总接收流量 + .outSpeed(totalBytesSent) // 总发送流量 + .ipv4InSpeed(null) // 无IP配置,无法区分IPv4/IPv6流量 + .ipv4OutSpeed(null) + .ipv6InSpeed(null) + .ipv6OutSpeed(null) + .speed(speed) + .duplex(duplex) + .timestamp(timestamp) + .build(); + + System.out.println("-----------------------------------------"); + return netVO; + + } catch (Exception e) { + System.err.println("处理无IP网卡 " + interfaceName + " 失败: " + e.getMessage()); + return null; + } + } + + /** + * 获取网卡MAC地址 + */ + private String getMacAddress(String interfaceName) { + try { + Path macPath = Paths.get("/sys/class/net", interfaceName, "address"); + if (Files.exists(macPath)) { + String mac = Files.readAllLines(macPath).get(0).trim(); + return mac.isEmpty() ? null : mac; + } + } catch (Exception e) { + System.err.println("获取MAC地址失败: " + e.getMessage()); + } + return null; + } + + /** + * 获取网卡状态 + */ + private String getInterfaceStatus(String interfaceName) { + try { + Path operstatePath = Paths.get("/sys/class/net", interfaceName, "operstate"); + if (Files.exists(operstatePath)) { + String state = Files.readAllLines(operstatePath).get(0).trim(); + return "up".equalsIgnoreCase(state) ? "已连接" : "未连接"; + } + } catch (Exception e) { + System.err.println("获取网卡状态失败: " + e.getMessage()); + } + return "未知"; + } + /** * 获取iptables统计信息 - 使用命令过滤模式优化 */ @@ -266,6 +439,9 @@ public class NetServiceImpl implements NetService { return null; } + /** + * 获取网卡协商模式 + */ public static Map getNetworkMode(String interfaceName) { Map result = new HashMap<>(); ProcessBuilder pb = new ProcessBuilder("ethtool", interfaceName); diff --git a/src/main/java/com/tongran/agent/client/utils/AgentUtil.java b/src/main/java/com/tongran/agent/client/utils/AgentUtil.java index 5c3aac7..8b4b0b0 100644 --- a/src/main/java/com/tongran/agent/client/utils/AgentUtil.java +++ b/src/main/java/com/tongran/agent/client/utils/AgentUtil.java @@ -338,6 +338,16 @@ public class AgentUtil { while (interfaces.hasMoreElements()) { NetworkInterface ni = interfaces.nextElement(); + AssertLog.info("interfaceName:{}", ni.getName()); + Enumeration children = ni.getSubInterfaces(); + while (children.hasMoreElements()) { + NetworkInterface child = children.nextElement(); + AssertLog.info("子interfaceName:{}", child.getName()); + } + System.out.println("显示名称: " + ni.getDisplayName()); + System.out.println("是否启用: " + ni.isUp()); + System.out.println("是否虚拟: " + ni.isVirtual()); + System.out.println("MTU: " + ni.getMTU()); String ipv4 = getIPv4Address(ni); String ipv6 = getGlobalIPv6Address(ni); AssertLog.info("ipv4={},接口状态={}",ipv4,ni.isUp());