通常绑定本机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()); } }