1、优化agent注册解析公网ip超时问题。
2、优化agent注册网卡上报逻辑。
This commit is contained in:
@@ -26,6 +26,11 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class AgentUtil {
|
||||
|
||||
// 存储网关信息:接口名 -> 网关IP
|
||||
private static Map<String, String> gatewayMap = new HashMap<>();
|
||||
|
||||
// 正则表达式匹配:当前 IP:xxx.xxx.xxx.xxx 来自于:中国 江苏省 南京市 电信
|
||||
private static final String REGEX = "来自于:(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)";
|
||||
@Resource
|
||||
private GlobalConfig globalConfig;
|
||||
|
||||
@@ -252,25 +257,62 @@ public class AgentUtil {
|
||||
return swapped;
|
||||
}
|
||||
|
||||
// 存储网关信息:接口名 -> 网关IP
|
||||
private static Map<String, String> gatewayMap = new HashMap<>();
|
||||
/**
|
||||
* 检查有效网卡是否只有一个
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasOnlyOneValidNetworkInterface() {
|
||||
try {
|
||||
int validInterfaceCount = 0;
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
|
||||
// 正则表达式匹配:当前 IP:xxx.xxx.xxx.xxx 来自于:中国 江苏省 南京市 电信
|
||||
private static final String REGEX = "来自于:(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)";
|
||||
while (interfaces.hasMoreElements()) {
|
||||
NetworkInterface ni = interfaces.nextElement();
|
||||
String name = ni.getName();
|
||||
|
||||
// 1. 跳过回环、虚拟、关闭的接口
|
||||
if (ni.isLoopback() || ni.isVirtual() || !ni.isUp()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. 判断是否为 Ethernet
|
||||
if (!isEthernetInterface(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. 检查物理链路状态
|
||||
if (!isInterfaceConnected(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. 检查是否有IPv4地址
|
||||
String ipv4 = getIPv4Address(ni);
|
||||
if ("N/A".equals(ipv4)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 有效接口计数+1
|
||||
validInterfaceCount++;
|
||||
|
||||
// 如果已经超过1个,直接返回false
|
||||
if (validInterfaceCount > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 只有一个有效接口
|
||||
return validInterfaceCount == 1;
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("判断有效网络接口数量失败:{}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 收集所有 Ethernet 类型网卡信息
|
||||
*/
|
||||
public static List<NetworkInterfaceInfo> collectNetworkInfo() throws Exception {
|
||||
List<NetworkInterfaceInfo> result = new ArrayList<>();
|
||||
// String publicIp = getPublicIp(); // 获取公网 IP(全局出口)
|
||||
// String ipInfo = PublicIpFetcher.getPublicIp();
|
||||
// String publicIp = PublicIpFetcher.extractIp(ipInfo);
|
||||
// if (publicIp != null) {
|
||||
// System.out.println("公网 IP: " + publicIp);
|
||||
// } else {
|
||||
// System.out.println("未能提取 IP 地址");
|
||||
// }
|
||||
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
|
||||
while (interfaces.hasMoreElements()) {
|
||||
@@ -293,27 +335,35 @@ public class AgentUtil {
|
||||
|
||||
// 检查IP4信息
|
||||
if (ipv4.equals("N/A")) continue;
|
||||
|
||||
String gateway = getGatewayAddress();
|
||||
String gateway = null;
|
||||
if(hasOnlyOneValidNetworkInterface()){
|
||||
gateway = getGatewayAddress();
|
||||
}else{
|
||||
gateway = getGateway(name, "www.baidu.com");
|
||||
}
|
||||
AssertLog.info("ipv4={},网关={}",ipv4,gateway);
|
||||
// 检查IP4信息
|
||||
if (gateway.equals("N/A")) continue;
|
||||
if ("N/A".equals(gateway)) continue;
|
||||
|
||||
// 添加临时路由 过滤没有ipv4的接口
|
||||
boolean flag = addTempRoute(ipv4, name, gateway);
|
||||
if (!flag) continue;
|
||||
// boolean flag = addTempRoute(ipv4, name, gateway);
|
||||
// if (!flag) continue;
|
||||
|
||||
String ipInfo = PublicIpFetcher.getPublicIp();
|
||||
String publicIp = PublicIpFetcher.extractIp(ipInfo);
|
||||
if (publicIp != null) {
|
||||
System.out.println("公网 IP: " + publicIp);
|
||||
} else {
|
||||
System.out.println("未能提取 IP 地址");
|
||||
String publicIp = null;
|
||||
String ipInfo = null;
|
||||
if(gateway != null){
|
||||
ipInfo = PublicIpFetcher.getPublicIp();
|
||||
publicIp = PublicIpFetcher.extractIp(ipInfo);
|
||||
if (publicIp != null) {
|
||||
AssertLog.info("公网 IP: {}", publicIp);
|
||||
} else {
|
||||
AssertLog.info("未能提取 IP 地址");
|
||||
}
|
||||
if (StringUtils.isBlank(publicIp)) continue;
|
||||
}
|
||||
if (StringUtils.isBlank(publicIp)) continue;
|
||||
|
||||
// 删除临时路由
|
||||
delTempRoute(ipv4, name, gateway);
|
||||
// delTempRoute(ipv4, name, gateway);
|
||||
|
||||
|
||||
NetworkInterfaceInfo info = NetworkInterfaceInfo.builder()
|
||||
@@ -328,24 +378,29 @@ public class AgentUtil {
|
||||
|
||||
// 如果有公网 IP,查询归属地
|
||||
if (publicIp != null && !publicIp.isEmpty()) {
|
||||
Pattern pattern = Pattern.compile(REGEX);
|
||||
Matcher matcher = pattern.matcher(ipInfo);
|
||||
if (matcher.find()) {
|
||||
// 提取归属地信息
|
||||
PublicIpFetcher.IpLocationInfo location = PublicIpFetcher.extractLocation(ipInfo);
|
||||
info.setProvince(location.getProvince());
|
||||
info.setCity(location.getCity());
|
||||
info.setCarrier(location.getCarrier());
|
||||
// Pattern pattern = Pattern.compile(REGEX);
|
||||
// Matcher matcher = pattern.matcher(ipInfo);
|
||||
// if (matcher.find()) {
|
||||
// group(1): 国家(通常是“中国”)
|
||||
// group(2): 省份
|
||||
// group(3): 城市
|
||||
// group(4): 运营商
|
||||
String province = matcher.group(2);
|
||||
String city = matcher.group(3);
|
||||
String isp = matcher.group(4);
|
||||
// 去掉可能的标点符号(如句号)
|
||||
province = province.replaceAll("[。]", "");
|
||||
city = city.replaceAll("[。]", "");
|
||||
isp = isp.replaceAll("[。]", "");
|
||||
info.setCarrier(isp);
|
||||
info.setProvince(province);
|
||||
info.setCity(city);
|
||||
}
|
||||
// String province = matcher.group(2);
|
||||
// String city = matcher.group(3);
|
||||
// String isp = matcher.group(4);
|
||||
// // 去掉可能的标点符号(如句号)
|
||||
// province = province.replaceAll("[。]", "");
|
||||
// city = city.replaceAll("[。]", "");
|
||||
// isp = isp.replaceAll("[。]", "");
|
||||
// info.setCarrier(isp);
|
||||
// info.setProvince(province);
|
||||
// info.setCity(city);
|
||||
// }
|
||||
// ipInfo.substring(ipInfo.indexOf("来自于:")+4,ipInfo.length())
|
||||
// JSONObject location = queryIpLocation(publicIp);
|
||||
// if (location != null) {
|
||||
@@ -491,6 +546,55 @@ public class AgentUtil {
|
||||
}
|
||||
return "N/A";
|
||||
}
|
||||
public static String getGateway(String interfaceName, String target) {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[]{"traceroute", "-i", interfaceName, "-m", "1", target}
|
||||
);
|
||||
process.waitFor();
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream())
|
||||
);
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.trim().startsWith("1")) {
|
||||
// 检查是否全是星号
|
||||
if (line.contains("* * *")) {
|
||||
AssertLog.info("traceroute 探测完成,网卡名称:{},无网关", interfaceName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 提取网关IP地址
|
||||
// 示例行: "1 8.8.8.8 3.737 ms 3.940 ms 4.128 ms"
|
||||
Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
|
||||
if (matcher.find()) {
|
||||
String gatewayIp = matcher.group(0);
|
||||
AssertLog.info("traceroute 探测完成,网卡名称:{},网关IP:{}", interfaceName, gatewayIp);
|
||||
return gatewayIp;
|
||||
}
|
||||
|
||||
// 如果没有匹配到IP格式,尝试查找主机名
|
||||
// 行格式可能是: "1 gateway.local (192.168.1.1) 0.5 ms"
|
||||
String[] parts = line.trim().split("\\s+");
|
||||
if (parts.length >= 2 && !parts[1].equals("*")) {
|
||||
String gateway = parts[1];
|
||||
AssertLog.info("traceroute 探测完成,网卡名称:{},网关:{}", interfaceName, gateway);
|
||||
return gateway;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssertLog.info("traceroute 探测完成,网卡名称:{},未找到网关信息", interfaceName);
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.info("traceroute 探测失败,网卡名称:{},详情:{}", interfaceName, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查接口是否“已连接”(物理链路状态)
|
||||
private static boolean isInterfaceConnected(String interfaceName) {
|
||||
|
||||
@@ -4,37 +4,141 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PublicIpFetcher {
|
||||
|
||||
private static final String IP_SERVICE_URL = "https://myip.ipip.net";
|
||||
private static final int TIMEOUT_MS = 10_000; // 10秒超时
|
||||
// 主备IP查询服务
|
||||
private static final String PRIMARY_IP_SERVICE = "https://myip.ipip.net";
|
||||
private static final String FALLBACK_IP_SERVICE = "http://cip.cc";
|
||||
|
||||
private static final int TIMEOUT_MS = 8_000; // 8秒超时
|
||||
private static final int CURL_TIMEOUT_MS = 5_000; // curl命令执行超时
|
||||
|
||||
// 正则表达式匹配
|
||||
private static final String IPV4_PATTERN = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})";
|
||||
private static final Pattern IP_PATTERN = Pattern.compile(IPV4_PATTERN);
|
||||
private static final Pattern CIPCC_PATTERN = Pattern.compile(
|
||||
"IP\\s*:\\s*" + IPV4_PATTERN + "\\s*地址\\s*:\\s*([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s*运营商\\s*:\\s*([^\\r\\n]+)"
|
||||
);
|
||||
private static final Pattern IPIP_PATTERN = Pattern.compile(
|
||||
"当前 IP:\\s*" + IPV4_PATTERN + "\\s*来自于:([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)"
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取公网 IP(包含归属地信息)
|
||||
*
|
||||
* @return IP 信息字符串,如 "当前 IP:112.96.15.145,来自于:中国 广东省 深圳市 联通"
|
||||
* @throws IOException 如果网络请求失败
|
||||
* 获取公网 IP 信息(带降级策略)
|
||||
* 1. 首先尝试 myip.ipip.net
|
||||
* 2. 如果超时或失败,执行 curl cip.cc
|
||||
* 3. 如果都失败,返回本地IP
|
||||
*/
|
||||
public static String getPublicIp() throws IOException {
|
||||
URL url = new URL(IP_SERVICE_URL);
|
||||
public static String getPublicIp() {
|
||||
// 方法1: 尝试主服务
|
||||
String ipInfo = tryPrimaryService();
|
||||
if (ipInfo != null && !ipInfo.isEmpty()) {
|
||||
return ipInfo;
|
||||
}
|
||||
|
||||
// 方法2: 尝试备用服务
|
||||
ipInfo = tryFallbackService();
|
||||
if (ipInfo != null && !ipInfo.isEmpty()) {
|
||||
return ipInfo;
|
||||
}
|
||||
|
||||
// 方法3: 返回本地IP
|
||||
return getLocalIpInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试主服务 (myip.ipip.net)
|
||||
*/
|
||||
private static String tryPrimaryService() {
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
Future<String> future = executor.submit(() -> {
|
||||
try {
|
||||
AssertLog.info("myip.ipip.net采集IP信息成功");
|
||||
return fetchFromUrl(PRIMARY_IP_SERVICE, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("主服务请求失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
AssertLog.error("主服务请求超时");
|
||||
future.cancel(true);
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("主服务执行异常: {}", e.getMessage());
|
||||
} finally {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试备用服务 (curl cip.cc)
|
||||
*/
|
||||
private static String tryFallbackService() {
|
||||
try {
|
||||
Process process = new ProcessBuilder("curl", "-s", "--max-time", "5", FALLBACK_IP_SERVICE)
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
|
||||
// 等待进程完成
|
||||
boolean finished = process.waitFor(CURL_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
|
||||
if (finished && process.exitValue() == 0) {
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()))) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
result.append(line).append("\n");
|
||||
}
|
||||
AssertLog.info("curl cip.cc采集IP信息成功");
|
||||
return parseCipCcResult(result.toString());
|
||||
}
|
||||
} else {
|
||||
if (!finished) {
|
||||
process.destroyForcibly();
|
||||
}
|
||||
AssertLog.error("curl命令执行失败");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
AssertLog.error("执行curl命令IO异常: {}", e.getMessage());
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
AssertLog.error("curl命令被中断");
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("备用服务异常: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从HTTP URL获取IP信息
|
||||
*/
|
||||
private static String fetchFromUrl(String urlString, String charset) throws IOException {
|
||||
URL url = new URL(urlString);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 设置请求方法
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(TIMEOUT_MS);
|
||||
connection.setReadTimeout(TIMEOUT_MS);
|
||||
|
||||
// 发起请求
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != 200) {
|
||||
throw new IOException("HTTP " + responseCode + " from " + IP_SERVICE_URL);
|
||||
throw new IOException("HTTP " + responseCode + " from " + urlString);
|
||||
}
|
||||
|
||||
// 读取响应(注意:myip.ipip.net 返回的是 GBK 编码)
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream(), "UTF-8"))) { // 使用 GBK 解码
|
||||
new InputStreamReader(connection.getInputStream(), charset))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
@@ -45,42 +149,142 @@ public class PublicIpFetcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从返回文本中提取纯 IP 地址(如 112.96.15.145)
|
||||
*
|
||||
* @param ipInfo 来自 getPublicIp() 的完整信息
|
||||
* @return 纯 IP 字符串,提取失败返回 null
|
||||
* 解析cip.cc的结果
|
||||
*/
|
||||
private static String parseCipCcResult(String result) {
|
||||
if (result == null || result.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Matcher matcher = CIPCC_PATTERN.matcher(result);
|
||||
if (matcher.find()) {
|
||||
String ip = matcher.group(1);
|
||||
String country = matcher.group(2);
|
||||
String province = matcher.group(3);
|
||||
String city = matcher.group(4);
|
||||
String carrier = matcher.group(5);
|
||||
|
||||
// 构建类似ipip.net的格式
|
||||
return String.format("当前 IP:%s 来自于:%s %s %s %s",
|
||||
ip, country, province, city, carrier);
|
||||
}
|
||||
return result; // 返回原始结果
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地IP信息
|
||||
*/
|
||||
private static String getLocalIpInfo() {
|
||||
try {
|
||||
String localIp = InetAddress.getLocalHost().getHostAddress();
|
||||
AssertLog.info("当前 IP:{} 来自于:本地网络", localIp);
|
||||
return localIp;
|
||||
} catch (UnknownHostException e) {
|
||||
AssertLog.error("当前IP获取失败:{}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从IP信息中提取IP地址
|
||||
*/
|
||||
public static String extractIp(String ipInfo) {
|
||||
if (ipInfo == null || ipInfo.isEmpty()) return null;
|
||||
|
||||
// 匹配 IP 地址的正则
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
|
||||
java.util.regex.Matcher matcher = pattern.matcher(ipInfo);
|
||||
Matcher matcher = IP_PATTERN.matcher(ipInfo);
|
||||
return matcher.find() ? matcher.group(1) : null;
|
||||
}
|
||||
|
||||
// === 使用示例 ===
|
||||
/**
|
||||
* 从IP信息中提取归属地信息
|
||||
*/
|
||||
public static IpLocationInfo extractLocation(String ipInfo) {
|
||||
IpLocationInfo info = new IpLocationInfo();
|
||||
|
||||
if (ipInfo == null || ipInfo.isEmpty()) {
|
||||
return info;
|
||||
}
|
||||
|
||||
// 尝试匹配ipip.net格式
|
||||
Matcher ipipMatcher = IPIP_PATTERN.matcher(ipInfo);
|
||||
if (ipipMatcher.find()) {
|
||||
info.ip = ipipMatcher.group(1);
|
||||
info.country = ipipMatcher.group(2);
|
||||
info.province = ipipMatcher.group(3);
|
||||
info.city = ipipMatcher.group(4);
|
||||
info.carrier = ipipMatcher.group(5);
|
||||
return info;
|
||||
}
|
||||
|
||||
// 尝试匹配cip.cc格式
|
||||
Matcher cipMatcher = CIPCC_PATTERN.matcher(ipInfo);
|
||||
if (cipMatcher.find()) {
|
||||
info.ip = cipMatcher.group(1);
|
||||
info.country = cipMatcher.group(2);
|
||||
info.province = cipMatcher.group(3);
|
||||
info.city = cipMatcher.group(4);
|
||||
info.carrier = cipMatcher.group(5);
|
||||
return info;
|
||||
}
|
||||
|
||||
// 如果都不匹配,只提取IP
|
||||
String ip = extractIp(ipInfo);
|
||||
if (ip != null) {
|
||||
info.ip = ip;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整的归属地信息
|
||||
*/
|
||||
public static class IpLocationInfo {
|
||||
public String ip;
|
||||
public String country;
|
||||
public String province;
|
||||
public String city;
|
||||
public String carrier;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("IP: %s, 国家: %s, 省份: %s, 城市: %s, 运营商: %s",
|
||||
ip, country, province, city, carrier);
|
||||
}
|
||||
|
||||
public String getProvince() {
|
||||
return province != null ? province.replaceAll("[。\\s]", "") : "";
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city != null ? city.replaceAll("[。\\s]", "") : "";
|
||||
}
|
||||
|
||||
public String getCarrier() {
|
||||
return carrier != null ? carrier.replaceAll("[。\\s]", "") : "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用示例
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
String ipInfo = getPublicIp();
|
||||
System.out.println("完整信息: " + ipInfo);
|
||||
System.out.println("开始获取公网IP信息...");
|
||||
|
||||
String pureIp = extractIp(ipInfo);
|
||||
if (pureIp != null) {
|
||||
System.out.println("公网 IP: " + pureIp);
|
||||
} else {
|
||||
System.out.println("未能提取 IP 地址");
|
||||
}
|
||||
String province = "";
|
||||
String city = "";
|
||||
String carrier = "";
|
||||
String ipInfo = getPublicIp();
|
||||
System.out.println("完整信息: " + ipInfo);
|
||||
|
||||
System.out.println(ipInfo.substring(ipInfo.indexOf("来自于:")+4,ipInfo.length()));
|
||||
String pureIp = extractIp(ipInfo);
|
||||
System.out.println("公网 IP: " + (pureIp != null ? pureIp : "获取失败"));
|
||||
|
||||
IpLocationInfo location = extractLocation(ipInfo);
|
||||
System.out.println(location);
|
||||
|
||||
} catch (IOException e) {
|
||||
System.err.println("获取公网 IP 失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
// 提取需要的字段
|
||||
if (location.ip != null) {
|
||||
System.out.println("省份: " + location.getProvince());
|
||||
System.out.println("城市: " + location.getCity());
|
||||
System.out.println("运营商: " + location.getCarrier());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user