SnowFlake.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. try
  59. {
  60. var mac = SystemInfo.GetMacAddress().FirstOrDefault(a => a.GetAddressBytes().Length > 0);
  61. if (mac != null)
  62. {
  63. var bytes = mac.GetAddressBytes();
  64. SetMachienId(bytes[4] << 2 | bytes[5]);
  65. }
  66. else
  67. {
  68. var ip = SystemInfo.GetLocalUsedIP();
  69. if (ip != null)
  70. {
  71. var bytes = ip.GetAddressBytes();
  72. SetMachienId(bytes[3]);
  73. }
  74. }
  75. }
  76. catch
  77. {
  78. SetMachienId(0);
  79. }
  80. }
  81. /// <summary>
  82. /// 构造函数
  83. /// </summary>
  84. /// <param name="machineId">机器码</param>
  85. public SnowFlake(long machineId)
  86. {
  87. SetMachienId(machineId);
  88. }
  89. public static void SetMachienId(long machineId)
  90. {
  91. if (machineId >= 0)
  92. {
  93. if (machineId > 1024)
  94. {
  95. throw new Exception("机器码ID非法");
  96. }
  97. _machineId = machineId;
  98. }
  99. }
  100. /// <summary>
  101. /// 设置数制格式化器
  102. /// </summary>
  103. /// <param name="nf"></param>
  104. public static void SetNumberFormater(NumberFormater nf)
  105. {
  106. _numberFormater = nf;
  107. }
  108. /// <summary>
  109. /// 设置起始偏移量
  110. /// </summary>
  111. /// <param name="offset"></param>
  112. public static void SetInitialOffset(long offset)
  113. {
  114. _offset = offset;
  115. }
  116. /// <summary>
  117. /// 获取长整形的ID
  118. /// </summary>
  119. /// <returns></returns>
  120. public long GetLongId()
  121. {
  122. lock (SyncRoot)
  123. {
  124. var timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  125. if (_lastTimestamp == timestamp)
  126. {
  127. //同一毫秒中生成ID
  128. _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
  129. if (_sequence == 0)
  130. {
  131. //一毫秒内产生的ID计数已达上限,等待下一毫秒
  132. timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  133. }
  134. }
  135. else
  136. {
  137. //不同毫秒生成ID
  138. _sequence = 0L;
  139. }
  140. _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  141. long id = ((timestamp - Twepoch) << (int)TimestampLeft) | (_machineId << MachineLeft) | _sequence;
  142. return id - _offset;
  143. }
  144. }
  145. /// <summary>
  146. /// 获取一个字符串表示形式的id
  147. /// </summary>
  148. /// <returns></returns>
  149. public string GetUniqueId()
  150. {
  151. return _numberFormater.ToString(GetLongId());
  152. }
  153. /// <summary>
  154. /// 获取一个字符串表示形式的id
  155. /// </summary>
  156. /// <param name="maxLength">最大长度,至少6位</param>
  157. /// <returns></returns>
  158. public string GetUniqueShortId(int maxLength = 8)
  159. {
  160. if (maxLength < 6)
  161. {
  162. throw new ArgumentException("最大长度至少需要6位");
  163. }
  164. string id = GetUniqueId();
  165. int index = id.Length - maxLength;
  166. if (index < 0)
  167. {
  168. index = 0;
  169. }
  170. return id.Substring(index);
  171. }
  172. }
  173. }