通常绑定本机ip地址 一般如下
InetSocketAddress address = new InetSocketAddress(port);
Channel serverChannel = bootstrap.bind(address);
InetSocketAddress默认使用的是什么ip呢?看看内部代码就明白了:
public InetSocketAddress(int port) {
this(InetAddress.anyLocalAddress(), port);
}
InetAddress.anyLocalAddress()一般就是0.0.0.0/0.0.0.0,如果我们有两块网卡,一块内网,一块外网,那么都能访问这个socket,这通常是不安全的。那么通过InetAddress.getLocalHost().getHostAddress()呢?
结果悲剧了,使用上面的代码取回的是127.0.0.1。
好了,看看dubbo是怎么解决,dubbo获取本机ip地址的方法封装在com.alibaba.dubbo.common.utils.NetUtils类里面。
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NetUtils {
private static final Logger logger = LoggerFactory.getLogger(NetUtils.class);
private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");
private static final Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$");
public static final String ANYHOST = "0.0.0.0";
public static final String LOCALHOST = "127.0.0.1";
private static boolean isValidAddress(InetAddress address) {
if (address == null || address.isLoopbackAddress()) return false;
String name = address.getHostAddress();
return (name != null && !ANYHOST.equals(name) && !LOCALHOST.equals(name) && IP_PATTERN.matcher(name).matches());
}
public static boolean isLocalHost(String host) {
return host != null && (LOCAL_IP_PATTERN.matcher(host).matches() || host.equalsIgnoreCase("localhost"));
}
public static boolean isAnyHost(String host) {
return "0.0.0.0".equals(host);
}
private static volatile InetAddress LOCAL_ADDRESS = null;
/**
* 遍历本地网卡,返回第一个合理的IP。
*
* @return 本地网卡IP
*/
public static InetAddress getLocalAddress() {
if (LOCAL_ADDRESS != null) {
return LOCAL_ADDRESS;
}
InetAddress localAddress = getLocalAddress0();
LOCAL_ADDRESS = localAddress;
return localAddress;
}
private static InetAddress getLocalAddress0() {
InetAddress localAddress = null;
try {
localAddress = InetAddress.getLocalHost();
if (isValidAddress(localAddress)) {
return localAddress;
}
} catch (Throwable e) {
logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
}
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
if (interfaces != null) {
while (interfaces.hasMoreElements()) {
try {
NetworkInterface network = interfaces.nextElement();
Enumeration<InetAddress> addresses = network.getInetAddresses();
if (addresses != null) {
while (addresses.hasMoreElements()) {
try {
InetAddress address = addresses.nextElement();
if (isValidAddress(address)) {
return address;
}
} catch (Throwable e) {
logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
}
}
}
} catch (Throwable e) {
logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
}
}
}
} catch (Throwable e) {
logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
}
logger.error("Could not get local host ip address, will use 127.0.0.1 instead.");
return localAddress;
}
}
简单的说就是通过NetworkInterface遍历网卡address,然后通过isValidAddress校验ip是否正常即可。需要注意的一点是,dubbo通过Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$")判断ip是否合法,也就是说不能保证只返回内网ip!
我把代码改了一下,保证只返回内网ip:
package com.duitang.dboss.util;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
/**
*
* @author yunpeng
*
*/
public class NetUtil {
private static volatile InetAddress LOCAL_ADDRESS = null;
/**
* 遍历本地网卡,返回内网IP。
*
* @return 本地网卡IP
*/
public static InetAddress getLocalAddress() {
if (LOCAL_ADDRESS != null) {
return LOCAL_ADDRESS;
}
InetAddress localAddress = getLocalAddress0();
LOCAL_ADDRESS = localAddress;
return localAddress;
}
private static InetAddress getLocalAddress0() {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface network = interfaces.nextElement();
Enumeration<InetAddress> addresses = network.getInetAddresses();
while (addresses != null && addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address != null && !address.isLoopbackAddress()) {
String name = address.getHostAddress();
if (name != null && name.startsWith("192.168")) {
return address;
}
}
}
}
} catch (SocketException e) {
throw new RuntimeException(e);
}
throw new RuntimeException("Could not get local host ip address!");
}
public static void main(String[] args) {
System.out.println(NetUtil.getLocalAddress().getHostAddress());
}
}