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
相关产品推荐
相关产品推荐

