尽pipe使用NetworkInterface
, InterfaceAddress
, InetAddress
组合来查找机器IP地址的线程有很多,但是我的情况却有所不同。
我需要确定与特定(给定)目标进行通信时使用的传出IP地址。 我必须假设主机上有多个具有多个IP地址的接口。 这是我可以想象的现实生活场景中的最佳逼近,其中我必须提供给远程机器,远程机器只有通过IP地址才知道它可能用于到达我的主机。
到目前为止,我没有发现这个任务的纯Java解决scheme。 有了我非常有限的Java知识,我看不到分析可能的路由选项的简单方法。 这就是为什么在Linux上,我只是在外部执行并parsing类似的东西:
ip -o route get 10.10.xx.xx
这反过来会给我想要的价值(“src xx.xx.xx.xx”):
10.10.xx.xx dev eth1 src 10.20.xx.xx \ cache mtu 1500 advmss 1460 hoplimit 64
我的问题是如果有一个本地的方式来实现相同的结果,而不需要调用上面的外部命令。 如果没有,那么你对Windows的build议是什么?
我也尝试使用InetAddress.isReachable(...)
和外部ping
与给定的源地址,但前者在我的环境中的防火墙失败时回落到TCP回声,而另一个提供误报。 (在我testing的虚拟机上,我有一个接口直接绑定到主机networking,第二个接口通过VM主机作为网桥(NAT),所以ping这两个路由通过主机进行路由的操作并不支持。
我将不胜感激任何build议如何继续…
最后,我结束了解析路由表(仅IP4,没有静态路由)。 这是一个代码片段,也许对别人有用。 更具体的路线优于更通用的路线。 对于相同的网络部分长度来说,最好的度量是胜利
private static String findOutgoingIpForGivenAdress(String remoteIP) { final String COMMAND = "route print -4"; List<RouteInfo> routes = new ArrayList<>(); try { Process exec = Runtime.getRuntime().exec(COMMAND); BufferedReader reader = new BufferedReader(new InputStreamReader(exec.getInputStream())); String localIP = null; String line; /* examples: 0.0.0.0 0.0.0.0 10.172.180.1 10.172.180.36 20 0.0.0.0 0.0.0.0 10.187.20.1 10.187.20.225 25 10.172.180.0 255.255.255.0 On-link 10.172.180.36 276 10.172.180.36 255.255.255.255 On-link 10.172.180.36 276 */ Pattern p = Pattern.compile("^\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+\\S+?\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(\\d+)\\s*$"); while ((line = reader.readLine()) != null) { Matcher match = p.matcher(line); if (match.matches()) { String network = match.group(1); String mask = match.group(2); String address = match.group(3); short maskLength = 0; boolean networkMatch = network.contentEquals("0.0.0.0"); if (!networkMatch) { SubnetUtils subnet = new SubnetUtils(network, mask); SubnetUtils.SubnetInfo info = subnet.getInfo(); networkMatch = info.isInRange(remoteIP); maskLength = Short.valueOf(info.getCidrSignature().split("/")[1]); } if (networkMatch) { short metric = Short.valueOf(match.group(4)); routes.add(new RouteInfo(address, maskLength, metric)); } } } Collections.sort(routes); for (RouteInfo route : routes) { } if (!routes.isEmpty()) return routes.get(0).source; if (localIP != null) return localIP; } catch (Exception ex) { ex.printStackTrace(); } return null; }
还有RouteInfo
助手类:
public class RouteInfo implements Comparable<RouteInfo> { public final String source; public final short maskLength; public final short metric; public RouteInfo(String src, short mask, short mtr) { source = src; maskLength = mask; metric = mtr; } @Override public int compareTo(RouteInfo ri) { if (ri.maskLength != maskLength) return ri.maskLength - maskLength; return metric - ri.metric; } }