关于JAVA取本机ip的一些总结

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

猜你喜欢

转载自san-yun.iteye.com/blog/1941909