// tcp_server.go package main import ( "fmt" "io" "net" "regexp" "strconv" "strings" "sync" "time" ) // 客户端信息结构 type ClientInfo struct { IP string // IP地址 Port string // 端口 LastSeen time.Time // 最后活跃时间 } // 客户端列表(使用互斥锁保护的映射) var ( clientsMutex sync.Mutex clients = make(map[string]*ClientInfo) ) // StartTCPServer 启动TCP服务器 func StartTCPServer(address string) error { listener, err := net.Listen("tcp", address) if err != nil { return err } // 启动客户端清理 startClientCleanup() Logger.Printf("TCP服务器已启动,正在监听 %s\n", address) for { conn, err := listener.Accept() if err != nil { Logger.Printf("接受连接失败: %v", err) continue } go handleConnection(conn) } } // handleConnection 处理客户端连接 func handleConnection(conn net.Conn) { defer conn.Close() // 获取客户端信息 remoteAddr := conn.RemoteAddr().String() Logger.Printf("新的客户端连接: %s", remoteAddr) // 添加到在线客户端列表 addClient(remoteAddr) buffer := make([]byte, 1024) for { // 读取数据 n, err := conn.Read(buffer) if err != nil { if err != io.EOF { Logger.Printf("从客户端读取失败 %s: %v", remoteAddr, err) } else { Logger.Printf("客户端断开连接 %s", remoteAddr) } removeClient(remoteAddr) break } // 将字节数据转换为字符串,并记录原始数据 rawData := string(buffer[:n]) TCPDataLogger.Printf("从客户端 %s 接收到原始数据: %s", remoteAddr, rawData) // 尝试解析数据 sensorID, x, y, z, err := parseData(rawData) if err == nil { TCPDataLogger.Printf("解析成功 - 客户端: %s, 传感器ID: %d, 值: X=%.3f, Y=%.3f, Z=%.3f", remoteAddr, sensorID, x, y, z) // 保存数据到数据库 if err := SaveSensorData(sensorID, x, y, z); err != nil { Logger.Printf("保存传感器数据失败: %v", err) } } else { TCPDataLogger.Printf("无法解析从客户端 %s 接收到的数据: %s, 错误: %v", remoteAddr, rawData, err) } // 发送响应 resp := "OK\n" if _, err := conn.Write([]byte(resp)); err != nil { Logger.Printf("发送响应到客户端 %s 失败: %v", remoteAddr, err) removeClient(remoteAddr) break } // 更新客户端最后活跃时间 updateClientLastSeen(remoteAddr) } } // parseData 使用正则表达式解析传感器数据 func parseData(data string) (int, float64, float64, float64, error) { // 使用正则表达式匹配数据格式 pattern := regexp.MustCompile(`(\d+):([-]?\d+\.\d+),\s*([-]?\d+\.\d+),\s*([-]?\d+\.\d+)`) matches := pattern.FindStringSubmatch(data) if len(matches) != 5 { return 0, 0, 0, 0, fmt.Errorf("数据格式不正确: %s", data) } // 解析传感器ID和三个浮点数值 sensorID, err := strconv.Atoi(matches[1]) if err != nil { return 0, 0, 0, 0, fmt.Errorf("解析传感器ID失败: %v", err) } x, err := strconv.ParseFloat(strings.TrimSpace(matches[2]), 64) if err != nil { return 0, 0, 0, 0, fmt.Errorf("解析X值失败: %v", err) } y, err := strconv.ParseFloat(strings.TrimSpace(matches[3]), 64) if err != nil { return 0, 0, 0, 0, fmt.Errorf("解析Y值失败: %v", err) } z, err := strconv.ParseFloat(strings.TrimSpace(matches[4]), 64) if err != nil { return 0, 0, 0, 0, fmt.Errorf("解析Z值失败: %v", err) } return sensorID, x, y, z, nil } // 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(), } 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.LastSeen = time.Now() 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) // 如果超过1天未活跃,则删除 if lastSeenDuration > 24*time.Hour { delete(clients, addr) continue } // 在线状态 - 10分钟内有活动 isOnline := lastSeenDuration < 10*time.Minute result = append(result, map[string]interface{}{ "address": addr, "ip": client.IP, "port": client.Port, "lastSeen": client.LastSeen, "isOnline": isOnline, "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 { return fmt.Sprintf("%d小时前", int(d.Hours())) } 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() } }() }