netmgrd.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. package netmgrd
  2. import "C"
  3. import (
  4. "sync"
  5. "sync/atomic"
  6. "time"
  7. modem "hnyfkj.com.cn/rtu/linux/air720u"
  8. "hnyfkj.com.cn/rtu/linux/baseapp"
  9. )
  10. const MODULE_NAME = "NetworkManager"
  11. var (
  12. isOnline atomic.Bool // 标记是否联网
  13. offlineStartTs atomic.Int64 // 离线开始时间
  14. isSyncNTPTimeOK atomic.Bool // 标记本地时间是否已同步成功
  15. curNetType NetType // 当前的网络类型: 有线、蜂窝
  16. mu1 sync.Mutex
  17. isRunning1 bool
  18. exitCh1 chan struct{}
  19. wg1 sync.WaitGroup
  20. )
  21. type NetType int
  22. const (
  23. NetNone NetType = iota
  24. NetEth // 有线网络
  25. NetLTE // 蜂窝网络
  26. )
  27. const (
  28. interval1 = time.Duration(1) * time.Second
  29. interval2 = time.Duration(5) * time.Second
  30. )
  31. func ModuleInit() {
  32. go serviceRun()
  33. }
  34. // 联网保持服务
  35. func serviceRun() {
  36. // 1, 首次连接网络
  37. openNetwork()
  38. // 2, 监控联网状态
  39. t := time.NewTimer(interval1)
  40. defer t.Stop()
  41. for {
  42. select {
  43. case <-t.C:
  44. // 3.1 切换网络-看情况
  45. eth0CableOK, _ := isEth0CableConnected()
  46. if (eth0CableOK && curNetType != NetEth) || (!eth0CableOK && curNetType != NetLTE) {
  47. baseapp.Logger.Warnf("[%s] 网络环境变化, 正在尝试切换网络...", MODULE_NAME)
  48. openNetwork()
  49. }
  50. // 3.2, 联网检测-看结果
  51. dnsOK, pingOK, tcpOK, httpOK := CheckNetwork()
  52. baseapp.Logger.Infof("[%s] 联网检测: DNS OK=%v, PING OK=%v, TCP OK=%v, HTTP OK=%v", MODULE_NAME, dnsOK, pingOK, tcpOK, httpOK)
  53. // 3.3, 联网成功-在线时
  54. if dnsOK && pingOK && tcpOK {
  55. isOnline.Store(true)
  56. offlineStartTs.Store(0)
  57. if isSyncNTPTimeOK.Load() {
  58. t.Reset(interval2)
  59. continue
  60. }
  61. err := SyncNTPTime()
  62. if err == nil {
  63. isSyncNTPTimeOK.Store(true)
  64. baseapp.Logger.Infof("[%s] NTP时间已同步", MODULE_NAME)
  65. t.Reset(interval2)
  66. continue
  67. } else {
  68. baseapp.Logger.Errorf("[%s] 同步NTP时间时有错误发生: %v!!", MODULE_NAME, err)
  69. t.Reset(interval1)
  70. continue
  71. }
  72. }
  73. // 3.4, 联网失败-离线时
  74. if isOnline.Load() { // 状态由"1"变为"0"
  75. isOnline.Store(false)
  76. offlineStartTs.Store(time.Now().UnixNano()) // 记录离线开始时间
  77. }
  78. if offlineDuration() >= (time.Duration(60) * time.Second) {
  79. baseapp.Logger.Warnf("[%s] 网络长时间断开, 正在重新连接...", MODULE_NAME)
  80. openNetwork()
  81. offlineStartTs.Store(time.Now().UnixNano()) // 重置离线开始时间
  82. }
  83. t.Reset(interval1)
  84. case <-baseapp.IsExit2():
  85. return
  86. } // select end
  87. } // for end
  88. }
  89. // 返回联网状态
  90. func IsInetAvailable() bool {
  91. return isOnline.Load()
  92. }
  93. // 时间是否同步
  94. func IsSyncedNtpTime() bool {
  95. return isSyncNTPTimeOK.Load()
  96. }
  97. // 等待所有成功
  98. func WaitAllOK(timeout time.Duration) bool {
  99. deadline := time.Now().Add(timeout)
  100. tick := 50 * time.Millisecond
  101. for {
  102. if IsInetAvailable() && IsSyncedNtpTime() {
  103. return true
  104. }
  105. remaining := time.Until(deadline)
  106. if remaining <= 0 {
  107. return false
  108. }
  109. sleep := min(tick, remaining)
  110. time.Sleep(sleep)
  111. }
  112. }
  113. // 返回断网时长
  114. func offlineDuration() time.Duration {
  115. if IsInetAvailable() {
  116. return 0
  117. }
  118. ts := offlineStartTs.Load()
  119. if ts == 0 {
  120. return 0
  121. }
  122. return time.Since(time.Unix(0, ts))
  123. }
  124. // 打开有线网络
  125. func openEth0Net() bool {
  126. mu1.Lock()
  127. defer mu1.Unlock()
  128. if isRunning1 {
  129. return true
  130. }
  131. killAllUdhcpc()
  132. err := disableEthBut0()
  133. if err != nil {
  134. baseapp.Logger.Errorf("[%s] 错误: %v!!", MODULE_NAME, err)
  135. return false
  136. }
  137. bExists, _ := udhcpcEth0Exists()
  138. if bExists {
  139. killEth0Udhcpc()
  140. }
  141. err = dialupEth0()
  142. if err != nil {
  143. baseapp.Logger.Errorf("[%s] 拨号连接\"eth0\"时发生错误: %v!!", MODULE_NAME, err)
  144. return false
  145. }
  146. ipv4, mask, err := getEth0Addr()
  147. if err != nil {
  148. baseapp.Logger.Errorf("[%s] 读取\"eth0\"地址时发生错误: %v!!", MODULE_NAME, err)
  149. return false
  150. }
  151. baseapp.Logger.Infof("[%s] \"eth0\"分配的地址: %s/%s", MODULE_NAME, ipv4, mask)
  152. exitCh1 = make(chan struct{})
  153. wg1.Add(1)
  154. go func() { // 启动携程守护"eth0"网卡上的 "udhcpc"后台服务进程
  155. defer wg1.Done()
  156. monitorEth0Udhcpc(exitCh1)
  157. }()
  158. isRunning1 = true
  159. return isRunning1
  160. }
  161. // 断开有线网络
  162. func closeEth0Net() {
  163. mu1.Lock()
  164. defer mu1.Unlock()
  165. if !isRunning1 {
  166. return
  167. }
  168. close(exitCh1)
  169. wg1.Wait() // 等待守护"eth0"网卡上的 "udhcpc"后台服务进程的携程退出
  170. bExists, _ := udhcpcEth0Exists()
  171. if bExists {
  172. killEth0Udhcpc()
  173. }
  174. isRunning1 = false
  175. }
  176. // 打开连接网络
  177. func openNetwork() {
  178. closeEth0Net()
  179. modem.CloseEth2Net()
  180. eth0CableOK, _ := isEth0CableConnected()
  181. if eth0CableOK && openEth0Net() {
  182. curNetType = NetEth
  183. baseapp.Logger.Infof("[%s] ✅ 有线网络已连接", MODULE_NAME)
  184. return
  185. }
  186. tryOpenLTE := func() bool {
  187. err := modem.EnableEth2()
  188. if err != nil {
  189. baseapp.Logger.Errorf("[%s] 启用\"eth2\"网卡时发生错误: %v!!", MODULE_NAME, err)
  190. return false
  191. }
  192. if eth2CableOK, _ := modem.IsEth2CableConnected(); eth2CableOK {
  193. if modem.OpenEth2Net() {
  194. return true
  195. }
  196. // 4G模组重新上电初始化后重试
  197. modem.ModuleExit()
  198. modem.ModuleInit(true)
  199. return modem.OpenEth2Net()
  200. }
  201. return false
  202. }
  203. if tryOpenLTE() {
  204. curNetType = NetLTE
  205. err := enableEth0() // 重新启用"eth0", 否则无法监听拔插网线
  206. if err != nil {
  207. baseapp.Logger.Errorf("[%s] 启用\"eth0\"网卡时发生错误: %v!!", MODULE_NAME, err)
  208. }
  209. baseapp.Logger.Infof("[%s] ✅ 蜂窝网络已连接", MODULE_NAME)
  210. return
  211. }
  212. curNetType = NetNone
  213. baseapp.Logger.Warnf("[%s] 没有可用的网络连接!", MODULE_NAME)
  214. }
  215. // 得到当前联网类型: 有线、蜂窝
  216. func GetCurrentNetType() NetType {
  217. return curNetType
  218. }
  219. //export RTU_IsInetAvailable
  220. func RTU_IsInetAvailable() C.int {
  221. if IsInetAvailable() {
  222. return 1
  223. }
  224. return 0
  225. }
  226. //export RTU_IsSyncedNtpTime
  227. func RTU_IsSyncedNtpTime() C.int {
  228. if IsSyncedNtpTime() {
  229. return 1
  230. }
  231. return 0
  232. }