zoukankan      html  css  js  c++  java
  • 如何获取本机IP

    GetLocalHost

    直接通过InetAddress.getLocalHost()来获取,其主要逻辑如下

    	InetAddress.getLocalHost();
    	String hostname = impl.getLocalHostName();
    	if(hostname.equals("localhost")){
    		return impl.loopvacjAddress();
    	}
    	InetAddress.getAddressesFromNameService(hostname, null);
    	nameService.lookupAllHostAddr(host);
    

    在linux中的hostname是个变量,由系统初始化的时候, 在shell启动脚本 “/etc/rc.d/rc.sysinit” 中实现,主要是读取“/etc/sysconfig/network” 中的HOSTNAME的值 可以通过命令 hostname xxx 修改 hostname。

    这里有几个注意点:

    1. 如果文件中没有hostname,那么会使用默认的localhost
    
    2. 如果发现hostname的值是localhost 或者 localhost.localdomain, 根据自己的实际ip查找/etc/hosts中这个ip对应的hostname。
    
    3. 如果没有,则使用localhost 或者localhost.localdomain
    

    如果hostname是localhost,就会直接返回环回地址,如IPv4的127.0.0.1

    如果不是的话,则会先看缓存里的CachedLocalHost的值,如果缓存的时间离现在小于5s的话,则直接返回缓存里的内容,如果间隔时间超过5s,则重新查询

    重新查询是通过NameService去获取IP地址的,具体的实现类是DNSNameService,其中NameServices是InetAddress是成员变量,通过static代码块初始化的

    主要实现都是通过native的系统调用,查看/etc/resolv.conf下配置的nameserver和/etc/hosts下面的配置,然后使用DNS协议查询,查询后将其缓存。

    如果DNS查询不到的话,会抛出异常,UnKnownHostName。

    一般来说,没有自己去进行一些主动的配置的话,会就拿到127.0.0.1这种IP,显然是无效IP

    获取所有网卡的IP

    换另外一种思路,通过本机网络设备所绑定的网卡来获取本机的IP

    	Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
    	if (interfaces != null) {
    		while (interfaces.hasMoreElements()) {
    			try {
    				NetworkInterface network = interfaces.nextElement();
    				if(network.isVirtual()){
        				continue;/**如果是虚拟网卡,排除此网卡*/
      				}
      				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);
    			}
    		}
    	}
    

    这种方法就是,拿到的是所有网络设备的属性,假装过滤虚拟网卡,找到第一个属于有效IP的地址。

    如何判断是有效IP?

    	LOCALHOST = "127.0.0.1";
    
    	ANYHOST = "0.0.0.0";
    
    	LOCAL_IP_PATTERN = Pattern.compile("127(\.\d{1,3}){3}$");
    
    	IP_PATTERN = Pattern.compile("\d{1,3}(\.\d{1,3}){3,5}$");
    

    但是有一点劣势就是,不知道哪块才是真正用来和外界通信的网卡,比如我的开发机

    就经常出现这个拿到192.168.122.1的情况,virbr0是一个虚拟网卡,可是java拿到他的时候,虚拟的属性却是false。

    当然,这块网卡可以卸载,不过不在讨论范围。

    这也是一个问题,这个网卡明明是虚拟网卡,但是java拿到它的时候,属性就不是虚拟的,没办法,谁让这个接口实质性调用的是一个native的getAll方法。

    通过连接远程端口

    最好的方式自然是通过Socket去连接一个远程端口,这样就能很方便地知道本机与外部通信时候使用的IP了。

    	try {
    		Socket socket = new Socket();
    		try {
    			SocketAddress addr = new InetSocketAddress(host, port);
    			socket.connect(addr, 1000);
    			return socket.getLocalAddress();
    		} finally {
    			try {
      				socket.close();
    			} catch (Throwable e) {
    			}
    		}
    	} catch (Exception e) {
    		LOGGER.warn("Failed to retrive local address by connecting to dest host,ip={},port={},e={}", host, port, e);
    	}
    

    这种方式拿到的本机IP就比较保险了

    当然, 比如你连接本机的端口,拿到的地址还会是127.0.0.1

    连接本地局域网内的机器,拿到的会是本机局域网段的地址,比如我的机器是10.97.26.154

    连接一个具有公网ip的机器的端口,拿到的还是本机局域网段的地址,比如我的机器是10.97.26.154

    其实这个,还是也拿到网卡的地址,当你使用哪个网卡去连接此端口的时候,就会得到哪个网卡所绑定的地址。

    IP地址绑定

    服务启动的时候,如果不确定应该绑定在哪个地址,则应该使用0.0.0.0,这样的话,通过所有本机的网卡的地址,都能访问此服务。

    如果绑定的是127.0.0.1的话,那么只端口只对本机提供服务。

  • 相关阅读:
    django 模型ManyToMany 关联的添加,删除,查询
    js 购物车的数量加减,对应的总价也随机变化
    `Java`中`abstract class`与`interface`区别
    基于Netty的IdleStateHandler实现Mqtt心跳
    由MQTT topic的正则表达式匹配引发的特殊字符"/"匹配思考
    Maven项目配置Logback输出JSON格式日志
    MySql定时备份脚本
    使用tcpdump监控http流量
    Linux磁盘信息查询及删除文件操作
    基于Morphia实现MongoDB按小时、按天聚合操作
  • 原文地址:https://www.cnblogs.com/flystar32/p/how_to_get_local_ip.html
Copyright © 2011-2022 走看看