概述
1.前言
最直接的思路是用CPU的序列号和主板编号来做,但是当你使用:sudo dmidecode -s baseboard-serial-number
来获取主板编号时,大部分情况下会给你返回:
To be filled by O.E.M.
这个提示是令人崩溃的,虽然它可以被服务器的代加工厂任意指定,可是加工厂就是不写。
2.首先获取CPU序列号
所以目前就剩下CPU的序列号了,CPU的序列号的获取方式很简单。CPU序号也有重复概率,网上有同志反映查到过同一批次服务器可能CPU ID 重复。
好的,下面我们给出两个主要操作系统下的获取方法。评论区的朋友们可以补充其它系统的,俺没有,就不献丑了。
2.1.Linux
dmidecode -t processor | grep 'ID'
2.2.Windows
wmic cpu get ProcessorId
3.MAC地址为什么没用?
主要原因是用户在连接多种通讯网络时,会拥有各式各样的Mac地址,使用哪一个都不好。并且心怀不轨的人还可以通过软件进行修改,达到伪装。具体的导论有很多,这里贴一个:How to get a unique computer identifier in Java (like disk ID or motherboard ID)?,这里面就提到,一个答主可以拥有下面这么多MAC地址:
lo MS TCP Loopback interface
eth1 Intel(R) 82579LM Gigabit Network Connection
eth2 VirtualBox Host-Only Ethernet Adapter
eth3 Sterownik serwera dostepu do sieci LAN Bluetooth
4.BIOS UUID
在关于硬件:在Windows和Linux上使用Python获取唯一的计算机ID一文中提到:在现代PC硬件上,通常在BIOS中存储有一个UUID
-在Linux
上,有一个命令行实用程序dmidecode
可以读取此信息。
是不是有点眼熟?dmidecode
这哥们又出现了,咱们简单介绍一下:
dmidecode在 Linux 系统下获取有关硬件方面的信息。dmidecode 遵循 SMBIOS/DMI 标准,以一种可读的方式dump出机器的DMI(Desktop Management Interface)信息, 其输出的信息包括 BIOS、系统、主板、处理器、内存、缓存等等, 既可以得到当前的配置,也可以得到系统支持的最大配置,比如说支持的最大内存数等。
好的,下面我们给出两个主要操作系统下的获取方法。评论区的朋友们可以补充其它系统的,俺没有,就不献丑了。
4.1.Linux
dmidecode -t system|grep UUID
4.2.Windows
wmic path win32_computersystemproduct get uuid
5.如何缩短编码长度?
现在CPU ID
和BIOS UUID
拼接在一起,已经52位长了,如果我们需要把它变成一个类似于1分钱优惠券激活码的东西让用户手动输入就太长了。
这个时候,我们需要进行摘要,摘要算法有哪些呢?有MD5(Message Digest)
、SHA(Secure Hash Algorithm)
、HMAC(Hash-based Message Authentication Code)
。记住一个简易技术选型方法——先试试MD5
行不行,不行再说。
6.Java代码
6.1.MachineCodeUtil.java
public class MachineCodeUtil {
public static final String LINUX_OS_NAME = "LINUX";
public static final String SYSTEM_PROPERTY_OS_NAME = "os.name";
public static void main(String[] args) {
System.out.println(getThisMachineCode());
System.out.println(getThisMachineCodeMd5());
}
/**
* 获取机器唯一识别码(CPU ID + BIOS UUID)
*
* @return 机器唯一识别码
*/
public static String getThisMachineCode() {
try {
return getCpuId() + getBiosUuid();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取机器码进行MD5摘要后的字符串
*
* @return
*/
public static String getThisMachineCodeMd5() {
try {
String thisMachineCode = getThisMachineCode();
String md5Upper = MD5Utils.MD5Upper(thisMachineCode);
return md5Upper;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取当前系统CPU序列,可区分linux系统和windows系统
*/
public static String getCpuId() throws IOException {
String cpuId;
// 获取当前操作系统名称
String os = System.getProperty(SYSTEM_PROPERTY_OS_NAME);
os = os.toUpperCase();
if (LINUX_OS_NAME.equals(os)) {
cpuId = getLinuxDmidecodeInfo("dmidecode -t processor | grep 'ID'", "ID", ":");
} else {
cpuId = getWindowsCpuId();
}
return cpuId.toUpperCase().replace(" ", "");
}
/**
* 获取linux系统
* dmidecode
* 命令的信息
*/
public static String getLinuxDmidecodeInfo(String cmd, String record, String symbol) throws IOException {
String execResult = executeLinuxCmd(cmd);
String[] infos = execResult.split("n");
for (String info : infos) {
info = info.trim();
if (info.contains(record)) {
info.replace(" ", "");
String[] sn = info.split(symbol);
return sn[1];
}
}
return null;
}
/**
* 执行Linux 命令
*
* @param cmd Linux 命令
* @return 命令结果信息
* @throws IOException 执行命令期间发生的IO异常
*/
public static String executeLinuxCmd(String cmd) throws IOException {
Runtime run = Runtime.getRuntime();
Process process;
process = run.exec(cmd);
InputStream processInputStream = process.getInputStream();
StringBuilder stringBuilder = new StringBuilder();
byte[] b = new byte[8192];
for (int n; (n = processInputStream.read(b)) != -1; ) {
stringBuilder.append(new String(b, 0, n));
}
processInputStream.close();
process.destroy();
return stringBuilder.toString();
}
/**
* 获取windows系统CPU序列
*/
public static String getWindowsCpuId() throws IOException {
Process process = Runtime.getRuntime().exec(
new String[]{"wmic", "cpu", "get", "ProcessorId"});
process.getOutputStream().close();
Scanner sc = new Scanner(process.getInputStream());
sc.next();
String serial = sc.next();
return serial;
}
/**
* 获取 BIOS UUID
*
* @return BIOS UUID
* @throws IOException 获取BIOS UUID期间的IO异常
*/
public static String getBiosUuid() throws IOException {
String cpuId;
// 获取当前操作系统名称
String os = System.getProperty("os.name");
os = os.toUpperCase();
if ("LINUX".equals(os)) {
cpuId = getLinuxDmidecodeInfo("dmidecode -t system | grep 'UUID'", "UUID", ":");
} else {
cpuId = getWindowsBiosUUID();
}
return cpuId.toUpperCase().replace(" ", "");
}
/**
* 获取windows系统 bios uuid
*
* @return
* @throws IOException
*/
public static String getWindowsBiosUUID() throws IOException {
Process process = Runtime.getRuntime().exec(
new String[]{"wmic", "path", "win32_computersystemproduct", "get", "uuid"});
process.getOutputStream().close();
Scanner sc = new Scanner(process.getInputStream());
sc.next();
String serial = sc.next();
return serial;
}
}
6.2.MD5Utils.java
这一部分完全copy自Java MD5 加密工具类。
/**
* MD5加密/验证工具类
*
*/
public class MD5Utils {
static final char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
static final char hexDigitsLower[] = { '0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
/**
* 对字符串 MD5 无盐值加密
*
* @param plainText
* 传入要加密的字符串
* @return
* MD5加密后生成32位(小写字母+数字)字符串
*/
public static String MD5Lower(String plainText) {
try {
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
md.update(plainText.getBytes());
// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值
return new BigInteger(1, md.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 对字符串 MD5 加密
*
* @param plainText
* 传入要加密的字符串
* @return
* MD5加密后生成32位(大写字母+数字)字符串
*/
public static String MD5Upper(String plainText) {
try {
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
md.update(plainText.getBytes());
// 获得密文
byte[] mdResult = md.digest();
// 把密文转换成十六进制的字符串形式
int j = mdResult.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = mdResult[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移
str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 对字符串 MD5 加盐值加密
*
* @param plainText
* 传入要加密的字符串
* @param saltValue
* 传入要加的盐值
* @return
* MD5加密后生成32位(小写字母+数字)字符串
*/
public static String MD5Lower(String plainText, String saltValue) {
try {
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
md.update(plainText.getBytes());
md.update(saltValue.getBytes());
// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值
return new BigInteger(1, md.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 对字符串 MD5 加盐值加密
*
* @param plainText
* 传入要加密的字符串
* @param saltValue
* 传入要加的盐值
* @return
* MD5加密后生成32位(大写字母+数字)字符串
*/
public static String MD5Upper(String plainText, String saltValue) {
try {
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
md.update(plainText.getBytes());
md.update(saltValue.getBytes());
// 获得密文
byte[] mdResult = md.digest();
// 把密文转换成十六进制的字符串形式
int j = mdResult.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = mdResult[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* MD5加密后生成32位(小写字母+数字)字符串
* 同 MD5Lower() 一样
*/
public final static String MD5(String plainText) {
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(plainText.getBytes("UTF-8"));
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigitsLower[byte0 >>> 4 & 0xf];
str[k++] = hexDigitsLower[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
/**
* 校验MD5码
*
* @param text
* 要校验的字符串
* @param md5
* md5值
* @return 校验结果
*/
public static boolean valid(String text, String md5) {
return md5.equals(MD5(text)) || md5.equals(MD5(text).toUpperCase());
}
}
7.最终效果
最终,你会获得类似于下面这样的字符串:
B6C15A6BF77C90244115E8E7B623F34C
当然了,如果你喜欢,可以每四位添加一个横杠,就像下面这样:
B6C1-5A6B-F77C-9024-4115-E8E7-B623-F34C
是不是有那味儿了?感觉下一秒钟就要拿着优惠券购买玛莎拉蒂了?
8.结语
另外,如果您能够保证用户不更换硬盘,硬盘的ID真的是不错的选择。
当我们获取到当前设备的唯一识别码,我们可以做很多有价值的事情。其实最有价值的还是去重,若后期有更好的方法,我也会分享给大家。希望看完博文的你没有bug。
参考资料
排名不分先后:
- How to Get the BIOS UUID
- dmidecode命令
- 使用Java实现信息摘要算法
- 主板型号:to be filled by O.E.M,这是什么情况?
- How to uniquely identify computer using C#?
最后
以上就是等待铃铛为你收集整理的Java:物联网终端机如何生成唯一识别码1.前言2.首先获取CPU序列号3.MAC地址为什么没用?4.BIOS UUID5.如何缩短编码长度?6.Java代码7.最终效果8.结语参考资料的全部内容,希望文章能够帮你解决Java:物联网终端机如何生成唯一识别码1.前言2.首先获取CPU序列号3.MAC地址为什么没用?4.BIOS UUID5.如何缩短编码长度?6.Java代码7.最终效果8.结语参考资料所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复