package tcp import ( "encoding/hex" "errors" "fmt" "go.uber.org/zap" "gorm.io/gorm" "net" Dev "server/dao/devices" deviceDao "server/dao/devices" promodel "server/model/common/devices" "server/model/common/request" "server/protocol" "server/utils/logger" "strings" "time" ) var ( devices = make(map[string]Device) // 存储连接的全局 map ) type Device struct { info deviceDao.Screens conn net.Conn lastTime time.Time stopChan chan struct{} // 添加停止通道 } func (s *Device) Start(conn net.Conn) { s.conn = conn s.stopChan = make(chan struct{}) go s.Process() go s.Handle() } func (s *Device) Process() { // 函数执行完之后关闭连接 defer s.conn.Close() for { buf := make([]byte, 256) // 将tcp连接读取到的数据读取到byte数组中, 返回读取到的byte的数目 n, err := s.conn.Read(buf) if err != nil { // 从客户端读取数据的过程中发生错误 这里如果没读到可以视为设备离线了 logger.Logger.Errorf("read from client failed [离线了], err:%v", err) break } data := hex.EncodeToString(buf[:n]) if !strings.Contains(strings.ToLower(data), "fe5c4b89") { continue } switch data[16:18] { case "61": logger.Logger.Debug("登录") // fe5c4b89 2a000000 62 00000000 17000000 31 23 32303233(年) 3035(月) 3135(日) 3031(星期) 3038(时) 3334(分) 3135(秒) 23 303630(心跳包时间) 23 ffff buffer := protocol.AuthDataPack{}.AuthLogin() // 通过sn 查设备是否存在 不存在return 存在就保存con 和 info screens, err := deviceDao.QueryScreenBySn(data[34:50]) if errors.Is(err, gorm.ErrRecordNotFound) { logger.Logger.Errorf("Process[case '61'] SN not found \n") break } s.info = screens devices[s.info.Sn] = *s s.conn.Write(buffer.Bytes()) case "91": logger.Logger.Debug("心跳") //判断内存devices中是否存储了设备(连接)信息 if _, exists := devices[data[34:50]]; !exists { //不存在 screens, err := deviceDao.QueryScreenBySn(data[34:50]) if errors.Is(err, gorm.ErrRecordNotFound) { logger.Logger.Errorf("Process[case '91'] SN not found \n") break } s.info = screens devices[s.info.Sn] = *s } if data[34:50] != s.info.Sn { continue } s.UpdateInfo(data[82:84], data[86:88], data[90:92]) default: fmt.Println("读取:", data) } } } func (s *Device) Handle() { defer s.conn.Close() t2 := time.NewTicker(3 * time.Minute) //在线监测 defer t2.Stop() for { select { case <-t2.C: state := request.DeviceStatus{ Status: 1, PlayStatus: 1, DisplayStatus: 1, SourceStatus: 1, } if time.Now().Add(-2*time.Minute).After(s.lastTime) || s.lastTime.IsZero() { //离线 state.Status = 0 state.PlayStatus = 0 state.DisplayStatus = 0 state.SourceStatus = 0 err := Dev.UpdateScreensStatus(s.info.ScreensCode, state) if err != nil { logger.Logger.Error("[Handle] UpdateScreensStatus err", zap.Error(err)) continue } s.conn.Close() close(s.stopChan) // 通知协程停止 delete(devices, s.info.Sn) //从内存中移除连接 return // 结束 Handle 协程 } else { logger.Logger.Debugf("%s在线", s.info.ScreensCode) } //修改数据库状态 err := Dev.UpdateScreensStatus(s.info.ScreensCode, state) if err != nil { logger.Logger.Error("[Handle] UpdateScreensStatus err", zap.Error(err)) continue } break default: continue } } } func (s *Device) UpdateInfo(playStatus, displayStatus, sourceStatus string) { play, display, source := 0, 0, 0 if playStatus == "31" { play = 1 } if displayStatus == "30" { display = 1 } if sourceStatus == "30" { source = 1 } s.info.Status = 1 s.info.PlayStatus = play s.info.DisplayStatus = display s.info.SourceStatus = source s.lastTime = time.Now() } func (s *Device) SwitchScreen(onOff int) error { pack := protocol.SwitchDataPack{Type: 0x52} //熄屏 if onOff == 1 { pack = protocol.SwitchDataPack{Type: 0x51} //亮屏 } buf := pack.SwitchScreens() //获取开关屏指令 _, err := s.conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("SwitchScreen write failed, err:%v", err) return err } return nil } func (s *Device) SendInternalCode(content []promodel.InternalCodeContent) error { pack := protocol.InternalCodeDataPack{} //获取要写入连接的字节数组 buf := pack.SendInternalCode(content) _, err := s.conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("SendInternalCode write failed, err:%v", err) return err } return nil } func (s *Device) VoiceBroad(broad string) error { pack := protocol.VoiceBroadDataPack{} buf := pack.VoiceBroad(broad) _, err := s.conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("VoiceBroad write failed, err:%v", err) return err } return nil } func SwitchScreen(sn string, onOff int) error { device := devices[sn] err := device.SwitchScreen(onOff) if err != nil { return err } return nil } func SendInternalCode(sn string, content []promodel.InternalCodeContent) error { device := devices[sn] err := device.SendInternalCode(content) if err != nil { return err } return nil } func VoiceBroad(sn string, broad string) error { device := devices[sn] err := device.VoiceBroad(broad) if err != nil { return err } return nil }