websocket_main.lua 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. --[[
  2. @module websocket_main
  3. @summary WebSocket client 主应用功能模块
  4. @version 1.1
  5. @date 2025.08.24
  6. @author 陈媛媛
  7. @usage
  8. 本文件为WebSocket client 主应用功能模块,核心业务逻辑为:
  9. 1、创建一个WebSocket client,连接server;
  10. 2、处理连接/异常逻辑,出现异常后执行重连动作;
  11. 3、调用websocket_receiver的外部接口websocket_receiver.proc,对接收到的数据进行处理;
  12. 4、调用sysplus.sendMsg接口,发送"CONNECT OK"和"DISCONNECTED"两种类型的"WEBSOCKET_EVENT"消息到websocket_sender的task,控制数据发送逻辑;
  13. 5、收到WebSocket数据后,执行sys.publish("FEED_NETWORK_WATCHDOG") 对网络环境检测看门狗功能模块进行喂狗;
  14. 本文件没有对外接口,直接在main.lua中require "websocket_main"就可以加载运行;
  15. ]]
  16. -- 加载WebSocket client数据接收功能模块
  17. local websocket_receiver = require "websocket_receiver"
  18. -- 加载WebSocket client数据发送功能模块
  19. local websocket_sender = require "websocket_sender"
  20. -- WebSocket服务器地址和端口
  21. -- 这里使用的地址和端口,会不定期重启或维护,仅能用作测试用途,不可商用,说不定哪一天就关闭了
  22. -- 用户开发项目时,替换为自己的商用服务器地址和端口
  23. -- 加密TCP链接 wss 表示加密
  24. local SERVER_URL = "wss://echo.airtun.air32.cn/ws/echo"
  25. -- 这是另外一个测试服务, 能响应websocket的二进制帧
  26. --local SERVER_URL = "ws://echo.airtun.air32.cn/ws/echo2"
  27. -- websocket_main的任务名
  28. local TASK_NAME = websocket_sender.TASK_NAME_PREFIX.."main"
  29. -- WebSocket client的事件回调函数
  30. local function websocket_client_event_cbfunc(ws_client, event, data, fin, opcode)
  31. log.info("WebSocket事件回调", ws_client, event, data, fin, opcode)
  32. -- WebSocket连接成功
  33. if event == "conack" then
  34. sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "CONNECT", true)
  35. -- 连接成功,通知网络环境检测看门狗功能模块进行喂狗
  36. sys.publish("FEED_NETWORK_WATCHDOG")
  37. -- 接收到服务器下发的数据
  38. -- data:string类型,表示接收到的数据
  39. -- fin:number类型,1表示是最后一个数据包,0表示还有后续数据包
  40. -- opcode:number类型,表示数据包类型(1-文本,2-二进制)
  41. elseif event == "recv" then
  42. -- 对接收到的数据处理
  43. websocket_receiver.proc(data, fin, opcode)
  44. -- 发送成功数据
  45. -- data:number类型,表示发送状态(通常为nil或0)
  46. elseif event == "sent" then
  47. log.info("WebSocket事件回调", "数据发送成功,发送确认")
  48. -- 发送消息通知 websocket sender task
  49. sysplus.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "SEND_OK", data)
  50. -- 服务器断开WebSocket连接
  51. elseif event == "disconnect" then
  52. -- 发送消息通知 websocket main task
  53. sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "DISCONNECTED", false)
  54. -- 严重异常,本地会主动断开连接
  55. -- data:string类型,表示具体的异常,有以下几种:
  56. -- "connect":tcp连接失败
  57. -- "tx":数据发送失败
  58. -- "other":其他异常
  59. elseif event == "error" then
  60. if data == "connect" then
  61. -- 发送消息通知 websocket main task,连接失败
  62. sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "CONNECT", false)
  63. elseif data == "other" or data == "tx" then
  64. -- 发送消息通知 websocket main task,出现异常
  65. sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "ERROR")
  66. end
  67. end
  68. end
  69. -- websocket main task 的任务处理函数
  70. local function websocket_client_main_task_func()
  71. local ws_client
  72. local result, msg
  73. while true do
  74. -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
  75. while not socket.adapter(socket.dft()) do
  76. log.warn("WebSocket主任务", "等待网络就绪", socket.dft())
  77. -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
  78. -- 或者等待1秒超时退出阻塞等待状态;
  79. -- 注意:此处的1000毫秒超时不要修改的更长;
  80. -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
  81. -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
  82. -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
  83. sys.waitUntil("IP_READY", 1000)
  84. end
  85. -- 检测到了IP_READY消息
  86. log.info("WebSocket主任务", "收到网络就绪消息", socket.dft())
  87. -- 清空此task绑定的消息队列中的未处理的消息
  88. sysplus.cleanMsg(TASK_NAME)
  89. -- 创建WebSocket client对象
  90. ws_client = websocket.create(nil, SERVER_URL)
  91. -- 如果创建WebSocket client对象失败
  92. if not ws_client then
  93. log.error("WebSocket主任务", "WebSocket创建失败")
  94. goto EXCEPTION_PROC
  95. end
  96. -- 设置自定义请求头
  97. --如果有需要,根据自己的实际需求,在此处配置请求头并打开注释。
  98. --if ws_client.headers then
  99. --ws_client:headers({Auth="Basic ABCDEGG"})
  100. --end
  101. -- 注册WebSocket client对象的事件回调函数
  102. ws_client:on(websocket_client_event_cbfunc)
  103. -- 连接server
  104. result = ws_client:connect()
  105. -- 如果连接server失败
  106. if not result then
  107. log.error("WebSocket主任务", "WebSocket连接失败")
  108. goto EXCEPTION_PROC
  109. end
  110. -- 连接、断开连接、异常等各种事件的处理调度逻辑
  111. while true do
  112. -- 等待"WEBSOCKET_EVENT"消息
  113. msg = sysplus.waitMsg(TASK_NAME, "WEBSOCKET_EVENT")
  114. log.info("WebSocket主任务等待消息", msg[2], msg[3], msg[4])
  115. -- connect连接结果
  116. -- msg[3]表示连接结果,true为连接成功,false为连接失败
  117. if msg[2] == "CONNECT" then
  118. -- WebSocket连接成功
  119. if msg[3] then
  120. log.info("WebSocket主任务", "连接成功")
  121. -- 通知websocket sender数据发送应用模块的task,WebSocket连接成功
  122. sysplus.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "CONNECT_OK", ws_client)
  123. -- WebSocket连接失败
  124. else
  125. log.info("WebSocket主任务", "连接失败")
  126. -- 退出循环,发起重连
  127. break
  128. end
  129. -- 需要主动关闭WebSocket连接
  130. -- 用户需要主动关闭WebSocket连接时,可以调用sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "CLOSE")
  131. elseif msg[2] == "CLOSE" then
  132. -- 主动断开WebSocket client连接
  133. ws_client:disconnect()
  134. -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间
  135. sys.wait(1000)
  136. break
  137. -- 被动关闭了WebSocket连接
  138. -- 被网络或者服务器断开了连接
  139. elseif msg[2] == "DISCONNECTED" then
  140. break
  141. -- 出现了其他异常
  142. elseif msg[2] == "ERROR" then
  143. break
  144. end
  145. end
  146. -- 出现异常
  147. ::EXCEPTION_PROC::
  148. -- 清空此task绑定的消息队列中的未处理的消息
  149. sysplus.cleanMsg(TASK_NAME)
  150. -- 通知websocket sender数据发送应用模块的task,WebSocket连接已经断开
  151. sysplus.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "DISCONNECTED")
  152. -- 如果存在WebSocket client对象
  153. if ws_client then
  154. -- 关闭WebSocket client,并且释放WebSocket client对象
  155. ws_client:close()
  156. ws_client = nil
  157. end
  158. -- 5秒后跳转到循环体开始位置,自动发起重连(与MQTT保持一致)
  159. sys.wait(5000)
  160. end
  161. end
  162. --创建并且启动一个task
  163. sysplus.taskInitEx(websocket_client_main_task_func, TASK_NAME)