You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala扫描IP段设备无法获取正确主机名的问题求助

问题

我写了一段Scala代码,用来扫描192.168.0.1至255网段内的可用设备,同时想打印设备的主机名。代码如下:

import java.net.{InetAddress, NetworkInterface}
import scala.collection.JavaConverters._

object GetIpMac {
  def main(args: Array[String]): Unit = {
    try {
      val network = "192.168.0"
      val range = (1 to 255)
      for (i <- range) {
        val ip = network + "." + i.toString
        val inet = InetAddress.getByName(ip)
        if (!inet.isLinkLocalAddress) {
          val ni = NetworkInterface.getByInetAddress(inet)
          if (ni != null) {
            val mac = ni.getHardwareAddress
            if (mac != null) {
              println(s"printing hostname ${inet.getHostName()}")
              println(ip + " " + mac.map("%02x".format(_)).mkString(":"))
            }
          }
        }
      }
    } catch {
      case ex: Exception => ex.printStackTrace()
    }
  }
}

本地运行后输出如下:

me@my-mac:~/Desktop$ sh scan.sh 
printing hostname 192.168.0.101
192.168.0.101 40:d2:53:99:78:67

可以看到输出的不是预期的主机名“my-mac”,而是对应的IP地址。请问这是什么原因?怎么才能正确打印出主机名?

原因分析

  • 反向DNS解析失效:inet.getHostName() 依赖DNS反向解析实现IP到主机名的映射。如果局域网内没有DNS服务器提供该IP的反向记录,或者设备未在DNS上注册主机名,Java会直接返回IP地址作为 fallback。
  • 本地hosts文件无对应绑定:若设备主机名my-mac未在本地/etc/hosts(Mac/Linux)或C:\Windows\System32\drivers\etc\hosts(Windows)中与192.168.0.101绑定,系统无法通过本地解析获取主机名,只能返回IP。
  • 局域网服务未开启:局域网内主机名解析通常依赖mDNS(Mac/Linux)或NetBIOS(Windows)服务,若目标设备未开启这类服务,无法通过广播机制获取主机名。

解决方案

方案1:配置本地hosts文件

在本地hosts文件中添加IP与主机名的绑定条目:

192.168.0.101 my-mac

修改后getHostName()就能直接从本地解析获取到主机名。

方案2:使用mDNS实现局域网解析

对于Mac/Linux设备,可借助mDNS(多播DNS)获取局域网内设备的主机名。可以使用JmDNS库来实现:

步骤1:添加依赖(sbt)

libraryDependencies += "javax.jmdns" % "jmdns" % "3.5.5"

步骤2:修改代码

import java.net.{InetAddress, NetworkInterface}
import javax.jmdns.JmDNS

object GetIpMac {
  def main(args: Array[String]): Unit = {
    try {
      val network = "192.168.0"
      val range = (1 to 255)
      val jmdns = JmDNS.create(InetAddress.getLocalHost())
      
      for (i <- range) {
        val ip = network + "." + i.toString
        val inet = InetAddress.getByName(ip)
        if (!inet.isLinkLocalAddress) {
          val ni = NetworkInterface.getByInetAddress(inet)
          if (ni != null) {
            val mac = ni.getHardwareAddress
            if (mac != null) {
              val hostname = jmdns.getHostName(inet)
              val displayName = if (hostname != null) hostname else inet.getHostName()
              println(s"printing hostname $displayName")
              println(ip + " " + mac.map("%02x".format(_)).mkString(":"))
            }
          }
        }
      }
      jmdns.close()
    } catch {
      case ex: Exception => ex.printStackTrace()
    }
  }
}

方案3:添加超时的反向解析

默认getHostName()无超时设置,若解析超时会直接返回IP。可以手动实现带超时的解析逻辑:

import java.net.InetAddress
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

def getHostNameWithTimeout(inet: InetAddress, timeout: Duration): String = {
  val future = Future { inet.getHostName() }
  try {
    Await.result(future, timeout)
  } catch {
    case _: Exception => inet.getHostAddress()
  }
}

在原代码中用这个方法替代inet.getHostName(),比如设置5秒超时:

println(s"printing hostname ${getHostNameWithTimeout(inet, 5.seconds)}")

内容的提问来源于stack exchange,提问作者joesan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:55:17