import java.io.*; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.*; /** * 注意事项: * ① 通过执行vbs 脚本(基于微软 Visual Basic的脚本语言) 来获取信息的方式只适用于windows系统,因为这种方式极度依赖 Windows脚本宿主环境的支持 * ② 关于临时目录,可通过 System.getProperty("java.io.tmpdir") 获取其具体位置。在window下通常为 C:\Users\Administrator\AppData\Local\Temp ,linux系统 下为 /tmp * ③ 命令方式和执行vbs 脚本的方式获取到的磁盘序列号并不相同,具体哪个是真实的序列号,有待验证 * ④ 或可尝试通过arp 命令来获取物理地址,但是arp查询的是高速缓存表的IP-MAC映射关系,包括了网络中与本机通信过的所有主机的MAC-IP映射关系(你可以ping一下远程主机建立相应的映射关系缓存),获取的地址信息或显得过于庞杂 * ⑤ 针对 Linux 系统主要通过执行命令的方式,不过由于系统架构的差异性,不同平台对同样的命令不一定都支持,需要根据具体系统测试、做兼容,这里提供一些常用查看命令—— * MAC 地址:ip link | grep link/ether | awk '{print $2}' * 磁盘序列号 hdparm -i /dev/sda | grep SerialNo 或 lsblk -a -o SERIAL * CPU序列号 dmidecode -t processor | grep 'ID' */ public class NetworkUtil { /** * 通过执行vbs 脚本获取系统主板序列号 */ public static String getMotherboardSerialByVbs() { StringBuilder result = new StringBuilder(); try { File file = File.createTempFile("realhowto", ".vbs"); file.deleteOnExit(); FileWriter fw = new FileWriter(file); String vbs = "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n" + "Set colItems = objWMIService.ExecQuery _ \n" + " (\"Select * from Win32_BaseBoard\") \n" + "For Each objItem in colItems \n" + " Wscript.Echo objItem.SerialNumber \n" + " exit for ' do the first cpu only! \n" + "Next \n"; fw.write(vbs); fw.close(); // Nologo 无标识执行 vbs 脚本 Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath()); BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = input.readLine()) != null) { result.append(line); } input.close(); } catch (Exception e) { e.printStackTrace(); } return result.toString().trim(); } /** * 通过执行 vbs 脚本(基于微软 Visual Basic的脚本语言) 来获磁盘序列号 */ public static String getWindowsDiskSerialByVbs() { StringBuilder result = new StringBuilder(); try { // 默认目录下创建临时文件,自己在任意位置创建vbs文件执行都可以 File file = File.createTempFile("tmp", ".vbs"); // 虚拟机退出时删除临时目录 file.deleteOnExit(); FileWriter fw = new FileWriter(file); String vbs = "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n" + "Set colItems = objWMIService.ExecQuery _ \n" + " (\"Select * from Win32_BaseBoard\") \n" + "For Each objItem in colItems \n" + " Wscript.Echo objItem.SerialNumber \n" + " exit for ' do the first cpu only! \n" + "Next \n"; fw.write(vbs); fw.flush(); fw.close(); Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath()); BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = input.readLine()) != null) { result.append(line); } input.close(); } catch (Exception e) { e.printStackTrace(); } return result.toString().trim(); } /** * 通过 vbs 脚本获取分区标记序列号,该序列号是由操作系统在格式化驱动器时创建的,而不是制造商的硬件序列号。 可参见 https://www.rgagnon.com/javadetails/java-0580.html */ public static String getWindowsDiskSerialByVbs(String drive) { StringBuilder result = new StringBuilder(); try { File file = File.createTempFile("tmp", ".vbs"); file.deleteOnExit(); FileWriter fw = new java.io.FileWriter(file); String vbs = "Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n" + "Set colDrives = objFSO.Drives\n" + "Set objDrive = colDrives.item(\"" + drive + "\")\n" + "Wscript.Echo objDrive.SerialNumber"; fw.write(vbs); fw.close(); Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath()); BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = input.readLine()) != null) { result.append(line); } input.close(); } catch (Exception e) { e.printStackTrace(); } return result.toString().trim(); } /** * 通过 cmd 命令获取序列号,不同Windows系统系统获取的序列号格式不尽一致,请自行测试 * ① 获取 磁盘 序列号 * wmic diskdrive get Serialnumber * wmic path win32_physicalmedia get SerialNumber * wmic path Win32_DiskDrive get SerialNumber * ② 获取 主板 序列号 * wmic baseboard get Serialnumber * ③ 获取 CPU 序列号 * wmic cpu get processorid */ public static String getWindowsSerialByCmd(String cmd) { try { Process process = Runtime.getRuntime().exec(cmd); InputStream inputStream = process.getInputStream(); Scanner scanner = new Scanner(inputStream); scanner.next(); return scanner.next(); } catch (IOException ex) { ex.printStackTrace(); } return ""; } /** * 在 Linux 上获取序列号 * lsblk -a -o SERIAL 在红帽系统(Red Hat)和基于红帽的CentOS虚拟机系统, 龙芯系统(mips64)上可以成功获取,但在 arm 系统 armv7l 等架构的某些机器中无法成功获取 不同平台获取的格式需要进行针对性的处理 */ public static String getDiskSerial(String cmd) { String execResult = getLinuxSerialByCmd(cmd); if (execResult == null) throw new RuntimeException("设备不支持该命令获取!"); String[] infos = execResult.split("\n"); if (infos.length > 1) { return infos[infos.length - 1]; } return null; } /** * 获取本地主机所有 IPv4 地址列表 * 注意事项: 由于NetworkInterface 只能枚举已启用的网卡信息,所以该方法只能获取到设备上已启用的网卡的 IP 地址 */ public static List<String> getLocalHostIPv4Addr() throws SocketException { List<String> ips = new ArrayList<>(); // 本机所有网络接口列表 这里有个坑,枚举出来的其实只是已经启用的网络接口 ,在Linux系统上也即 ifconfig 能看到的,通过 ip link 才能查看所有网络接口 Enumeration<NetworkInterface> enums = NetworkInterface.getNetworkInterfaces(); while (enums.hasMoreElements()) { NetworkInterface networkInterface = enums.nextElement(); // 枚举网络接口上所有地址的列表 一个网络接口可以绑定多个IP地址 Enumeration<InetAddress> addres = networkInterface.getInetAddresses(); while (addres.hasMoreElements()) { InetAddress inetAddress = addres.nextElement(); // 只查询IPv4地址接口,排除了IPv6和回送地址 String hostAddress = inetAddress.getHostAddress(); if (inetAddress instanceof Inet4Address && !"127.0.0.1".equals(hostAddress)) { ips.add(hostAddress); } } } return ips; } /** * 根据 IP 获取物理地址 * * @param bytes 原始 IP * @return mac 地址 */ public static String getMacByIp(byte[] bytes) { try { InetAddress inetAddress = InetAddress.getByAddress(bytes); NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress); byte[] hardwareAddress = networkInterface.getHardwareAddress(); return formartMac(hardwareAddress); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 根据 IP 获取物理地址 * * @param ip 点分四段 IP 地址 * @return mac 地址 */ public static String getMacByIp(String ip) { try { InetAddress inetAddress = InetAddress.getByName(ip); NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress); byte[] hardwareAddress = networkInterface.getHardwareAddress(); return formartMac(hardwareAddress); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 根据 网卡名 获取物理地址 * * @param eth 网卡名 * @return mac 地址 */ public static String getMacByNetCard(String eth) { try { NetworkInterface networkInterface = NetworkInterface.getByName(eth); byte[] hardwareAddress = networkInterface.getHardwareAddress(); return formartMac(hardwareAddress); } catch (Exception e) { e.printStackTrace(); } return null; } /** * mac 地址格式化 */ private static String formartMac(byte[] bytes) { if (bytes == null || bytes.length == 0) return ""; StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { if (i != 0) { sb.append("-"); } String temp = Integer.toHexString(bytes[i] & 0xFF); sb.append(temp.length() == 1 ? (0 + temp) : temp); } return sb.toString().toUpperCase(); } /** * 命令执行 */ private static String getLinuxSerialByCmd(String cmd) { try { Runtime run = Runtime.getRuntime(); Process process = run.exec(cmd); InputStream in = process.getInputStream(); StringBuilder sb = new StringBuilder(); byte[] b = new byte[1024]; for (int n; (n = in.read(b)) != -1;) { sb.append(new String(b, 0, n)); } in.close(); process.destroy(); return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } }
作者:陈本布衣
本文版权归作者和博客园共有,欢迎转载分享,但必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。