agent网卡探测方法修改。

网卡流量探测兼容没配IP的
This commit is contained in:
gaoyutao
2025-12-16 20:58:53 +08:00
parent 154e57a0a6
commit a9ca7f7ca6
4 changed files with 280 additions and 88 deletions
@@ -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<NetworkInterfaceInfo> infos = AgentUtil.collectNetworkInfo();
// List<NetworkInterfaceInfo> infos = AgentUtil.collectNetworkInfo();
List<NetworkInterfaceInfo> infos = NetworkInterfaceUtil.collectNetworkInfo();
JSONObject objects = new JSONObject();
objects.put("clientId", GlobalConfig.CLIENT_ID);
objects.put("sn", GlobalConfig.DEVICE_SN);
@@ -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<NetworkInterfaceInfo> infos = AgentUtil.collectNetworkInfo();
// List<NetworkInterfaceInfo> infos = AgentUtil.collectNetworkInfo();
List<NetworkInterfaceInfo> 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<NetworkInterfaceInfo> infos = AgentUtil.collectNetworkInfo();
// List<NetworkInterfaceInfo> infos = AgentUtil.collectNetworkInfo();
List<NetworkInterfaceInfo> 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<NetworkInterfaceInfo> infos = null;
try {
infos = AgentUtil.collectNetworkInfo();
// infos = AgentUtil.collectNetworkInfo();
infos = NetworkInterfaceUtil.collectNetworkInfo();
} catch (Exception e) {
e.printStackTrace();
}
@@ -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<String, Long> totalBytesRecvMap = new HashMap<>();
private Map<String, Long> totalBytesSentMap = new HashMap<>();
@Override
public List<NetVO> netList(long timestamp) {
List<NetVO> list = new ArrayList<>();
@@ -25,114 +31,281 @@ public class NetServiceImpl implements NetService {
HardwareAbstractionLayer hal = si.getHardware();
List<NetworkIF> networkIFs = hal.getNetworkIFs();
// 获取系统所有物理网卡
Set<String> allPhysicalInterfaces = getAllPhysicalInterfaces();
System.out.println("系统所有物理网卡: " + allPhysicalInterfaces);
System.out.println("OSHI识别的网卡: " + networkIFs.stream().map(NetworkIF::getName).collect(Collectors.toList()));
// 创建网卡名称到NetworkIF对象的映射
Map<String, NetworkIF> 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<String, Map<String, Long>> 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<String, Long> 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<String, String> 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<String> getAllPhysicalInterfaces() {
Set<String> interfaces = new HashSet<>();
Path netPath = Paths.get("/sys/class/net");
try (DirectoryStream<Path> 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<String, Map<String, Long>> 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<String, Long> 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<String, String> 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<String, String> 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<String, String> getNetworkMode(String interfaceName) {
Map<String, String> result = new HashMap<>();
ProcessBuilder pb = new ProcessBuilder("ethtool", interfaceName);
@@ -338,6 +338,16 @@ public class AgentUtil {
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
AssertLog.info("interfaceName{}", ni.getName());
Enumeration<NetworkInterface> 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());