123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- using Masuit.Tools.DateTimeExt;
- using Masuit.Tools.Strings;
- using System;
- using System.Linq;
- using System.Net.NetworkInformation;
- using Masuit.Tools.Hardware;
- using System.Collections.Generic;
- using System.Net.Sockets;
- namespace Masuit.Tools.Systems
- {
- /// <summary>
- /// 动态生产有规律的分布式ID
- /// </summary>
- public class SnowFlake
- {
- #region 私有字段
- private static long _offset; //起始偏移量
- private static long _machineId; //机器码
- private static long _sequence; //计数从零开始
- private static long _lastTimestamp = -1L; //最后时间戳
- private const long Twepoch = 687888001020L; //唯一时间随机量
- private const int MachineBits = 10; //机器码字节数
- private const int SequenceBits = 12; //计数器字节数,12个字节用来保存计数码
- private const int MachineLeft = SequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
- private const long TimestampLeft = MachineBits + SequenceBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
- private const long SequenceMask = -1L ^ -1L << SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
- private static readonly object SyncRoot = new(); //加锁对象
- private static NumberFormater _numberFormater = new(36);
- private static SnowFlake _snowFlake;
- #endregion 私有字段
- /// <summary>
- /// 获取一个新的id
- /// </summary>
- public static string NewId => GetInstance().GetUniqueId();
- /// <summary>
- /// 获取一个新的id
- /// </summary>
- public static long LongId => GetInstance().GetLongId();
- /// <summary>
- /// 创建一个实例
- /// </summary>
- /// <returns></returns>
- public static SnowFlake GetInstance()
- {
- return _snowFlake ??= new SnowFlake();
- }
- /// <summary>
- /// 默认构造函数
- /// </summary>
- public SnowFlake()
- {
- }
- /// <summary>
- /// 默认构造函数
- /// </summary>
- static SnowFlake()
- {
- try
- {
- var mac = SystemInfo.GetMacAddress().FirstOrDefault(a => a.GetAddressBytes().Length > 0);
- if (mac != null)
- {
- var bytes = mac.GetAddressBytes();
- SetMachienId(bytes[4] << 2 | bytes[5]);
- }
- else
- {
- var ip = SystemInfo.GetLocalUsedIP();
- if (ip != null)
- {
- var bytes = ip.GetAddressBytes();
- SetMachienId(bytes[3]);
- }
- }
- }
- catch
- {
- SetMachienId(0);
- }
- }
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="machineId">机器码</param>
- public SnowFlake(long machineId)
- {
- SetMachienId(machineId);
- }
- public static void SetMachienId(long machineId)
- {
- if (machineId >= 0)
- {
- if (machineId > 1024)
- {
- throw new Exception("机器码ID非法");
- }
- _machineId = machineId;
- }
- }
- /// <summary>
- /// 设置数制格式化器
- /// </summary>
- /// <param name="nf"></param>
- public static void SetNumberFormater(NumberFormater nf)
- {
- _numberFormater = nf;
- }
- /// <summary>
- /// 设置起始偏移量
- /// </summary>
- /// <param name="offset"></param>
- public static void SetInitialOffset(long offset)
- {
- _offset = offset;
- }
- /// <summary>
- /// 获取长整形的ID
- /// </summary>
- /// <returns></returns>
- public long GetLongId()
- {
- lock (SyncRoot)
- {
- var timestamp = DateTime.UtcNow.GetTotalMilliseconds();
- if (_lastTimestamp == timestamp)
- {
- //同一毫秒中生成ID
- _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
- if (_sequence == 0)
- {
- //一毫秒内产生的ID计数已达上限,等待下一毫秒
- timestamp = DateTime.UtcNow.GetTotalMilliseconds();
- }
- }
- else
- {
- //不同毫秒生成ID
- _sequence = 0L;
- }
- _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
- long id = ((timestamp - Twepoch) << (int)TimestampLeft) | (_machineId << MachineLeft) | _sequence;
- return id - _offset;
- }
- }
- /// <summary>
- /// 获取一个字符串表示形式的id
- /// </summary>
- /// <returns></returns>
- public string GetUniqueId()
- {
- return _numberFormater.ToString(GetLongId());
- }
- /// <summary>
- /// 获取一个字符串表示形式的id
- /// </summary>
- /// <param name="maxLength">最大长度,至少6位</param>
- /// <returns></returns>
- public string GetUniqueShortId(int maxLength = 8)
- {
- if (maxLength < 6)
- {
- throw new ArgumentException("最大长度至少需要6位");
- }
- string id = GetUniqueId();
- int index = id.Length - maxLength;
- if (index < 0)
- {
- index = 0;
- }
- return id.Substring(index);
- }
- }
- }
|