package main import ( "fmt" "net" "sync" "time" ) // 客户端信息结构 type ClientInfo struct { IP string // IP地址 Port string // 端口 LastSeen time.Time // 最后活跃时间 IsConnected bool // 是否当前连接 } // 客户端列表(使用互斥锁保护的映射) var ( clientsMutex sync.Mutex clients = make(map[string]*ClientInfo) ) // addClient 添加客户端 func addClient(addr string) { clientsMutex.Lock() defer clientsMutex.Unlock() host, port, err := net.SplitHostPort(addr) if err != nil { Logger.Printf("解析客户端地址失败 %s: %v", addr, err) host = addr port = "unknown" } clients[addr] = &ClientInfo{ IP: host, Port: port, LastSeen: time.Now(), IsConnected: true, } Logger.Printf("添加新客户端: %s", addr) } // updateClientLastSeen 更新客户端最后活跃时间 func updateClientLastSeen(addr string) { clientsMutex.Lock() defer clientsMutex.Unlock() if client, exists := clients[addr]; exists { client.LastSeen = time.Now() } } // removeClient 移除客户端(标记断开) func removeClient(addr string) { clientsMutex.Lock() defer clientsMutex.Unlock() if client, exists := clients[addr]; exists { client.IsConnected = false Logger.Printf("客户端断开连接: %s", addr) } } // getAllClients 获取所有客户端信息 func getAllClients() []map[string]interface{} { clientsMutex.Lock() defer clientsMutex.Unlock() now := time.Now() result := make([]map[string]interface{}, 0, len(clients)) for addr, client := range clients { lastSeenDuration := now.Sub(client.LastSeen) // 清理24小时前的记录 if lastSeenDuration > 24*time.Hour { delete(clients, addr) continue } // 连接状态判断:当前连接且2小时内活跃为在线 isOnline := client.IsConnected && lastSeenDuration < 2*time.Hour var connectionStatus string if isOnline { connectionStatus = "保持连接" } else if client.IsConnected { connectionStatus = "连接超时" } else { connectionStatus = "已断开" } result = append(result, map[string]interface{}{ "address": addr, "ip": client.IP, "port": client.Port, "lastSeen": client.LastSeen, "isOnline": isOnline, "connectionStatus": connectionStatus, "lastSeenFormatted": formatDuration(lastSeenDuration), }) } return result } // formatDuration 格式化持续时间为友好的字符串 func formatDuration(d time.Duration) string { if d < time.Minute { return "刚刚" } else if d < time.Hour { return fmt.Sprintf("%d分钟前", int(d.Minutes())) } else if d < 24*time.Hour { hours := int(d.Hours()) minutes := int(d.Minutes()) % 60 if minutes == 0 { return fmt.Sprintf("%d小时前", hours) } else { return fmt.Sprintf("%d小时%d分钟前", hours, minutes) } } else { return fmt.Sprintf("%d天前", int(d.Hours()/24)) } } // startClientCleanup 启动清理过期客户端的goroutine func startClientCleanup() { go func() { for { time.Sleep(1 * time.Hour) // 每小时检查一次 clientsMutex.Lock() now := time.Now() for addr, client := range clients { if now.Sub(client.LastSeen) > 24*time.Hour { delete(clients, addr) Logger.Printf("移除过期客户端: %s", addr) } } clientsMutex.Unlock() } }() }