generateip.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/go-nunu/nunu-layout-advanced/internal/repository"
  6. "github.com/sourcegraph/conc/pool"
  7. "math/rand"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "time"
  12. )
  13. type GenerateIpService interface {
  14. GenerateMultipleLoopbackIps(ctx context.Context, count ...int) ([]string, error)
  15. }
  16. func NewGenerateIpService(
  17. service *Service,
  18. gameShieldRepository repository.GameShieldRepository,
  19. ) GenerateIpService {
  20. return &generateIpService{
  21. Service: service,
  22. gameShieldRepository: gameShieldRepository,
  23. }
  24. }
  25. type generateIpService struct {
  26. *Service
  27. gameShieldRepository repository.GameShieldRepository
  28. }
  29. // GenerateMultipleLoopbackIps 生成多个唯一127.0.0.0/8范围IP地址
  30. // count 指定需要生成的IP地址数量,默认为10
  31. // 返回生成的唯一IP地址数组和可能的错误
  32. func (s *generateIpService) GenerateMultipleLoopbackIps(ctx context.Context, count ...int) ([]string, error) {
  33. requiredCount := 10
  34. if len(count) > 0 && count[0] > 0 {
  35. requiredCount = count[0]
  36. }
  37. maxAttempts := 1000 // 最大尝试次数
  38. attempts := 0
  39. // 使用互斥锁保护结果集
  40. var mu sync.Mutex
  41. collected := make([]string, 0, requiredCount)
  42. checkedSegments := make(map[string]struct{}, maxAttempts)
  43. // 使用一个固定的随机源以提高性能
  44. rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
  45. for len(collected) < requiredCount && attempts < maxAttempts {
  46. // 随机生成多个x/z段组合,批量处理
  47. candidates := make([]struct{ x, z int }, 0, 5)
  48. for i := 0; i < 5 && len(candidates) < 5; i++ {
  49. x := rnd.Intn(256)
  50. z := rnd.Intn(256)
  51. segmentKey := fmt.Sprintf("%d-%d", x, z)
  52. // 跳过已检查过的段
  53. mu.Lock()
  54. _, exists := checkedSegments[segmentKey]
  55. if !exists {
  56. checkedSegments[segmentKey] = struct{}{}
  57. mu.Unlock()
  58. candidates = append(candidates, struct{ x, z int }{x, z})
  59. } else {
  60. mu.Unlock()
  61. }
  62. }
  63. // 使用conc/pool包并发处理候选IP段
  64. // 创建一个工作池,限制并发数为4,并收集错误
  65. p := pool.New().WithMaxGoroutines(4).WithErrors()
  66. // 存储结果
  67. var results [][]string
  68. // 对每个候选项并发处理
  69. for _, candidate := range candidates {
  70. // 创建副本避免闭包捕获循环变量
  71. candidate := candidate
  72. p.Go(func() error {
  73. if ctx.Err() != nil {
  74. return ctx.Err()
  75. }
  76. x, z := candidate.x, candidate.z
  77. prefix := fmt.Sprintf("127.%d.%d.", x, z)
  78. // 查询数据库中该前缀已存在的IP
  79. existingIps, err := s.gameShieldRepository.GetGameShieldExistingIps(ctx, prefix)
  80. if err != nil {
  81. // 返回错误以便收集
  82. return fmt.Errorf("获取IP %s 前缀已存在的记录失败: %w", prefix, err)
  83. }
  84. // 使用map标记已存在的第四段
  85. existingFourth := make(map[int]bool, len(existingIps))
  86. for _, ip := range existingIps {
  87. parts := strings.Split(ip, ".")
  88. if len(parts) == 4 {
  89. fourth, err := strconv.Atoi(parts[3])
  90. if err == nil {
  91. // 排除127.0.0.1的情况
  92. if x == 0 && z == 0 && fourth == 1 {
  93. continue
  94. }
  95. existingFourth[fourth] = true
  96. }
  97. }
  98. }
  99. // 快速估算可用数量
  100. availableCount := 256 - len(existingFourth)
  101. // 排除127.0.0.1的特殊情况
  102. if x == 0 && z == 0 && !existingFourth[1] {
  103. availableCount--
  104. }
  105. // 如果可用数量太少,可以跳过
  106. if availableCount <= 0 {
  107. return nil
  108. }
  109. // 预分配足够大的切片避免多次扩容
  110. available := make([]string, 0, availableCount)
  111. // 如果可用数量很多,可以只收集部分,避免不必要的工作
  112. collectLimit := min(availableCount, requiredCount*2)
  113. collectCount := 0
  114. // 随机选择起始点,避免每次都从0开始
  115. startPoint := rnd.Intn(256)
  116. for i := 0; i < 256 && collectCount < collectLimit; i++ {
  117. fourth := (startPoint + i) % 256
  118. if existingFourth[fourth] {
  119. continue
  120. }
  121. // 确保不生成127.0.0.1
  122. if x == 0 && z == 0 && fourth == 1 {
  123. continue
  124. }
  125. available = append(available, fmt.Sprintf("127.%d.%d.%d", x, z, fourth))
  126. collectCount++
  127. }
  128. // 随机打乱结果
  129. for i := len(available) - 1; i > 0; i-- {
  130. j := rnd.Intn(i + 1)
  131. available[i], available[j] = available[j], available[i]
  132. }
  133. // 将结果添加到结果集
  134. mu.Lock()
  135. results = append(results, available)
  136. mu.Unlock()
  137. return nil
  138. })
  139. }
  140. // 等待所有goroutine完成并检查错误
  141. if err := p.Wait(); err != nil {
  142. // 这里可以选择记录错误但继续尝试,或者直接返回错误
  143. // 我们选择只有当收集的IP不足时才返回错误
  144. if len(collected) < requiredCount {
  145. // 如果已经是最后一次尝试且收集的IP不足,返回错误
  146. if attempts >= maxAttempts-1 {
  147. return nil, fmt.Errorf("生成IP地址失败: %w", err)
  148. }
  149. // 否则继续尝试下一批候选IP段
  150. }
  151. }
  152. // 收集结果
  153. for _, ips := range results {
  154. mu.Lock()
  155. for _, ip := range ips {
  156. if len(collected) >= requiredCount {
  157. break
  158. }
  159. collected = append(collected, ip)
  160. }
  161. mu.Unlock()
  162. }
  163. attempts++
  164. // 如果已经收集足够的IP,跳出循环
  165. mu.Lock()
  166. hasEnough := len(collected) >= requiredCount
  167. mu.Unlock()
  168. if hasEnough {
  169. break
  170. }
  171. }
  172. mu.Lock()
  173. defer mu.Unlock()
  174. if len(collected) < requiredCount {
  175. return nil, fmt.Errorf("无法生成足够的唯一IP地址,地址池可能已耗尽,仅生成了%d个", len(collected))
  176. }
  177. // 最终随机排序
  178. for i := len(collected) - 1; i > 0; i-- {
  179. j := rand.Intn(i + 1)
  180. collected[i], collected[j] = collected[j], collected[i]
  181. }
  182. return collected[:requiredCount], nil
  183. }