SnowFlake.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using Masuit.Tools.DateTimeExt;
  2. using Masuit.Tools.Strings;
  3. using System;
  4. using System.Linq;
  5. using System.Net.NetworkInformation;
  6. using Masuit.Tools.Hardware;
  7. using System.Collections.Generic;
  8. using System.Net.Sockets;
  9. namespace Masuit.Tools.Systems
  10. {
  11. /// <summary>
  12. /// 动态生产有规律的分布式ID
  13. /// </summary>
  14. public class SnowFlake
  15. {
  16. #region 私有字段
  17. private static long _offset; //起始偏移量
  18. private static long _machineId; //机器码
  19. private static long _sequence; //计数从零开始
  20. private static long _lastTimestamp = -1L; //最后时间戳
  21. private const long Twepoch = 687888001020L; //唯一时间随机量
  22. private const int MachineBits = 10; //机器码字节数
  23. private const int SequenceBits = 12; //计数器字节数,12个字节用来保存计数码
  24. private const int MachineLeft = SequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
  25. private const long TimestampLeft = MachineBits + SequenceBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
  26. private const long SequenceMask = -1L ^ -1L << SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
  27. private static readonly object SyncRoot = new(); //加锁对象
  28. private static NumberFormater _numberFormater = new(36);
  29. private static SnowFlake _snowFlake;
  30. #endregion 私有字段
  31. /// <summary>
  32. /// 获取一个新的id
  33. /// </summary>
  34. public static string NewId => GetInstance().GetUniqueId();
  35. /// <summary>
  36. /// 获取一个新的id
  37. /// </summary>
  38. public static long LongId => GetInstance().GetLongId();
  39. /// <summary>
  40. /// 创建一个实例
  41. /// </summary>
  42. /// <returns></returns>
  43. public static SnowFlake GetInstance()
  44. {
  45. return _snowFlake ??= new SnowFlake();
  46. }
  47. /// <summary>
  48. /// 默认构造函数
  49. /// </summary>
  50. public SnowFlake()
  51. {
  52. }
  53. /// <summary>
  54. /// 默认构造函数
  55. /// </summary>
  56. static SnowFlake()
  57. {
  58. var mac = SystemInfo.GetMacAddress().FirstOrDefault(a => a.GetAddressBytes().Length > 0);
  59. if (mac != null)
  60. {
  61. var bytes = mac.GetAddressBytes();
  62. SetMachienId(bytes[4] << 2 | bytes[5]);
  63. }
  64. else
  65. {
  66. var ip = SystemInfo.GetLocalUsedIP();
  67. if (ip != null)
  68. {
  69. var bytes = ip.GetAddressBytes();
  70. SetMachienId(bytes[3]);
  71. }
  72. }
  73. }
  74. /// <summary>
  75. /// 构造函数
  76. /// </summary>
  77. /// <param name="machineId">机器码</param>
  78. public SnowFlake(long machineId)
  79. {
  80. SetMachienId(machineId);
  81. }
  82. public static void SetMachienId(long machineId)
  83. {
  84. if (machineId >= 0)
  85. {
  86. if (machineId > 1024)
  87. {
  88. throw new Exception("机器码ID非法");
  89. }
  90. _machineId = machineId;
  91. }
  92. }
  93. /// <summary>
  94. /// 设置数制格式化器
  95. /// </summary>
  96. /// <param name="nf"></param>
  97. public static void SetNumberFormater(NumberFormater nf)
  98. {
  99. _numberFormater = nf;
  100. }
  101. /// <summary>
  102. /// 设置起始偏移量
  103. /// </summary>
  104. /// <param name="offset"></param>
  105. public static void SetInitialOffset(long offset)
  106. {
  107. _offset = offset;
  108. }
  109. /// <summary>
  110. /// 获取长整形的ID
  111. /// </summary>
  112. /// <returns></returns>
  113. public long GetLongId()
  114. {
  115. lock (SyncRoot)
  116. {
  117. var timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  118. if (_lastTimestamp == timestamp)
  119. {
  120. //同一毫秒中生成ID
  121. _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
  122. if (_sequence == 0)
  123. {
  124. //一毫秒内产生的ID计数已达上限,等待下一毫秒
  125. timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  126. }
  127. }
  128. else
  129. {
  130. //不同毫秒生成ID
  131. _sequence = 0L;
  132. }
  133. _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  134. long id = ((timestamp - Twepoch) << (int)TimestampLeft) | (_machineId << MachineLeft) | _sequence;
  135. return id - _offset;
  136. }
  137. }
  138. /// <summary>
  139. /// 获取一个字符串表示形式的id
  140. /// </summary>
  141. /// <returns></returns>
  142. public string GetUniqueId()
  143. {
  144. return _numberFormater.ToString(GetLongId());
  145. }
  146. /// <summary>
  147. /// 获取一个字符串表示形式的id
  148. /// </summary>
  149. /// <param name="maxLength">最大长度,至少6位</param>
  150. /// <returns></returns>
  151. public string GetUniqueShortId(int maxLength = 8)
  152. {
  153. if (maxLength < 6)
  154. {
  155. throw new ArgumentException("最大长度至少需要6位");
  156. }
  157. string id = GetUniqueId();
  158. int index = id.Length - maxLength;
  159. if (index < 0)
  160. {
  161. index = 0;
  162. }
  163. return id.Substring(index);
  164. }
  165. }
  166. }