package netmgrd import "C" import ( "sync" "sync/atomic" "time" "hnyfkj.com.cn/rtu/linux/baseapp" modem1 "hnyfkj.com.cn/rtu/linux/air720u" modem2 "hnyfkj.com.cn/rtu/linux/ec200u" ) const MODULE_NAME = "NetworkManager" var ( isOnline atomic.Bool // 标记是否联网 offlineStartTs atomic.Int64 // 离线开始时间 isSyncNTPTimeOK atomic.Bool // 标记本地时间是否已同步成功 curNetType NetType // 当前的网络类型: 有线、蜂窝 mu1 sync.Mutex isRunning1 bool exitCh1 chan struct{} wg1 sync.WaitGroup ) type NetType int const ( NetNone NetType = iota NetEth // 有线网络 NetLTE // 蜂窝网络 ) func (n NetType) String() string { switch n { case NetNone: return "无网络" case NetEth: return "有线网络" case NetLTE: return "蜂窝网络" default: return "未知网络" } } const ( interval1 = time.Duration(1) * time.Second interval2 = time.Duration(5) * time.Second ) func ModuleInit() { go serviceRun() } // 联网保持服务 func serviceRun() { // 1, 首次连接网络 openNetwork() // 2, 监控联网状态 t := time.NewTimer(interval1) defer t.Stop() for { select { case <-t.C: // 3.1 切换网络-看情况 eth0CableOK, _ := isEth0CableConnected() if (eth0CableOK && curNetType != NetEth) || (!eth0CableOK && curNetType != NetLTE) { baseapp.Logger.Warnf("[%s] 网络环境发生变化, 正在切换网络...", MODULE_NAME) openNetwork() } // 3.2, 联网检测-看结果 dnsOK, pingOK, tcpOK, httpOK := CheckNetwork() baseapp.Logger.Infof("[%s] 联网类型: %s, 检测结果: DNS OK=%v, PING OK=%v, TCP OK=%v, HTTP OK=%v", MODULE_NAME, curNetType.String(), dnsOK, pingOK, tcpOK, httpOK) // 3.3, 联网成功-在线时 if dnsOK && pingOK && tcpOK { isOnline.Store(true) offlineStartTs.Store(0) if isSyncNTPTimeOK.Load() { t.Reset(interval2) continue } err := SyncNTPTime() if err == nil { isSyncNTPTimeOK.Store(true) baseapp.Logger.Infof("[%s] NTP时间已同步", MODULE_NAME) t.Reset(interval2) continue } else { baseapp.Logger.Errorf("[%s] 同步NTP时间时有错误发生: %v!!", MODULE_NAME, err) t.Reset(interval1) continue } } // 3.4, 联网失败-离线时 if isOnline.Load() { // 状态由"1"变为"0" isOnline.Store(false) offlineStartTs.Store(time.Now().UnixNano()) // 记录离线开始时间 } if offlineDuration() >= (time.Duration(60) * time.Second) { baseapp.Logger.Warnf("[%s] 网络长时间的断开, 正在重新连接...", MODULE_NAME) openNetwork() offlineStartTs.Store(time.Now().UnixNano()) // 重置离线开始时间 } t.Reset(interval1) case <-baseapp.IsExit2(): return } // select end } // for end } // 返回联网状态 func IsInetAvailable() bool { return isOnline.Load() } // 时间是否同步 func IsSyncedNtpTime() bool { return isSyncNTPTimeOK.Load() } // 等待所有成功 func WaitAllOK(timeout time.Duration) bool { deadline := time.Now().Add(timeout) tick := 50 * time.Millisecond for { if IsInetAvailable() && IsSyncedNtpTime() { return true } remaining := time.Until(deadline) if remaining <= 0 { return false } sleep := min(tick, remaining) time.Sleep(sleep) } } // 返回断网时长 func offlineDuration() time.Duration { if IsInetAvailable() { return 0 } ts := offlineStartTs.Load() if ts == 0 { return 0 } return time.Since(time.Unix(0, ts)) } // 打开有线网络 func openEth0Net() bool { mu1.Lock() defer mu1.Unlock() if isRunning1 { return true } killAllUdhcpc() err := disableEthBut0() if err != nil { baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err) return false } bExists, _ := udhcpcEth0Exists() if bExists { killEth0Udhcpc() } err = dialupEth0() if err != nil { baseapp.Logger.Errorf("[%s] 拨号连接\"eth0\"时发生错误: %v!!", MODULE_NAME, err) return false } ipv4, mask, err := getEth0Addr() if err != nil { baseapp.Logger.Errorf("[%s] 读取\"eth0\"地址时发生错误: %v!!", MODULE_NAME, err) return false } baseapp.Logger.Infof("[%s] \"eth0\"分配的地址: %s/%s", MODULE_NAME, ipv4, mask) exitCh1 = make(chan struct{}) wg1.Add(1) go func() { // 启动携程守护"eth0"网卡上的 "udhcpc"后台服务进程 defer wg1.Done() monitorEth0Udhcpc(exitCh1) }() isRunning1 = true return isRunning1 } // 断开有线网络 func closeEth0Net() { mu1.Lock() defer mu1.Unlock() if !isRunning1 { return } close(exitCh1) wg1.Wait() // 等待守护"eth0"网卡上的 "udhcpc"后台服务进程的携程退出 bExists, _ := udhcpcEth0Exists() if bExists { killEth0Udhcpc() } isRunning1 = false } // 打开连接网络 func openNetwork() { closeEth0Net() switch curModemType { case Air720U: modem1.Stop4GNetwork() case EC200U: modem2.Stop4GNetwork() } eth0CableOK, _ := isEth0CableConnected() if eth0CableOK && openEth0Net() { curNetType = NetEth baseapp.Logger.Infof("[%s] ✅ 有线网络已连接", MODULE_NAME) return } start4GNetwork := func() bool { switch curModemType { case Air720U: if eth2CableOK, _ := modem1.Is4GCableConnected(); eth2CableOK { if modem1.Start4GNetwork() { return true } // 4G模组重新上电初始化后重试 modem1.ModuleExit() modem1.ModuleInit(true) return modem1.Start4GNetwork() } case EC200U: if usb0CableOK, _ := modem2.Is4GCableConnected(); usb0CableOK { if modem2.Start4GNetwork() { return true } // 4G模组重新上电初始化后重试 modem2.ModuleExit() modem2.ModuleInit(true) return modem2.Start4GNetwork() } } return false } if start4GNetwork() { curNetType = NetLTE baseapp.Logger.Infof("[%s] ✅ 蜂窝网络已连接", MODULE_NAME) return } curNetType = NetNone baseapp.Logger.Warnf("[%s] 没有可用的网络连接!", MODULE_NAME) } // 得到当前联网类型: 有线、蜂窝 func GetCurrentNetType() NetType { return curNetType } //export RTU_IsInetAvailable func RTU_IsInetAvailable() C.int { if IsInetAvailable() { return 1 } return 0 } //export RTU_IsSyncedNtpTime func RTU_IsSyncedNtpTime() C.int { if IsSyncedNtpTime() { return 1 } return 0 }