Java利用HostUtil工具类抓取本地IP地址(屏蔽无用地址)
一、现有的解决方法:通过黑名单屏蔽
会维护一个blackPrefixs的list类型,会屏蔽掉回环地址、ipv6以及以blackPrefixs中以"docker0", "br-", "veth"开头的地址。不是很灵活,经常会出现抓到了不以这些前缀开头的NetworkInterface,则会出现ip地址不是自己的地址的情况。
//核心逻辑
Iterator var5 = blackPrefix.iterator();
while(var5.hasNext()) {
String prefix = (String)var5.next();
if (networkInterface.getName().startsWith(prefix)) {
log.info("Network " + networkInterface.getName() + " will be ignored because it start with prefix " + prefix);
skip = true;
break;
}
}
二、通过判断是否可以连接公网
可以通过加上这样一层逻辑,在抓取到的非回环地址、非ipv6地址的基础上,进行一次socket连接。这种做法虽然可以找到能够连接外网的ipv4地址,但是比较耗费时间,另外就是客户的环境可能是与公网隔绝的环境。
try (SocketChannel socket = SocketChannel.open()) {
// again, use a big enough timeout
socket.socket().setSoTimeout(1000);
// bind the socket to your local interface
socket.bind(new InetSocketAddress(address, 8080));
// try to connect to *somewhere*
socket.connect(new InetSocketAddress("baidu.com", 80));
} catch (IOException ex) {
ex.printStackTrace();
continue;
}
三、给予用户一种使用方式
在console端,暴露出了business.properties配置文件,在其中定义了console.hostutil.blackPrefixs这个配置。在原来的HostUtil中的blackPrefixs利用spring的@value注解(这样还得给HostUtil类打上@Component),注入配置文件中的值,这样可以给予用户一种选择的权利,但是也不是最终的解决方案,最终的方案应该是用户无感知的那种。
private static List<String> blackPrefixs;
@Value("${console.hostutil.blackPrefixs}")
public void setBlackPrefixs(List<String> blackPrefixs) {
HostUtil.blackPrefixs = blackPrefixs;
}
## to ignore the useless network
console.hostutil.blackPrefixs="docker0", "br-", "veth", "bridge", "virbr"
附录HostUtil
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class HostUtil {
/**
* Need ignore other useless network's ip
*/
private static List<String> blackPrefixs;
private static String hostIpCache = null;
@Value("${console.hostutil.blackPrefixs}")
public void setBlackPrefixs(List<String> blackPrefixs) {
HostUtil.blackPrefixs = blackPrefixs;
}
public static String getHostIp() {
if (StringUtils.isNotBlank(hostIpCache)) {
return hostIpCache;
} else {
hostIpCache = getHostIpInner();
return hostIpCache;
}
}
private static String getHostIpInner() {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
String lastMatchIP = null;
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
boolean skip = false;
for (String prefix : blackPrefixs) {
if (networkInterface.getName().startsWith(prefix)) {
log.info("Network " + networkInterface.getName() + " will be ignored because it start with prefix " + prefix);
skip = true;
break;
}
}
if (skip) {
continue;
}
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr.isLoopbackAddress()) {
continue;
}
lastMatchIP = addr.getHostAddress();
if (!lastMatchIP.contains(":")) {
return lastMatchIP;// return IPv4 addr
}
}
}
if (StringUtils.isBlank(lastMatchIP)) {
return InetAddress.getLocalHost().getHostAddress();
} else {
return lastMatchIP;
}
} catch (Exception e) {
throw new RuntimeException("get host ip failed,msg:" + ExceptionUtils.getRootCauseMessage(e), e);
}
}
}