--[[ @module websocket_main @summary WebSocket client 主应用功能模块 @version 1.1 @date 2025.08.24 @author 陈媛媛 @usage 本文件为WebSocket client 主应用功能模块,核心业务逻辑为: 1、创建一个WebSocket client,连接server; 2、处理连接/异常逻辑,出现异常后执行重连动作; 3、调用websocket_receiver的外部接口websocket_receiver.proc,对接收到的数据进行处理; 4、调用sysplus.sendMsg接口,发送"CONNECT OK"和"DISCONNECTED"两种类型的"WEBSOCKET_EVENT"消息到websocket_sender的task,控制数据发送逻辑; 5、收到WebSocket数据后,执行sys.publish("FEED_NETWORK_WATCHDOG") 对网络环境检测看门狗功能模块进行喂狗; 本文件没有对外接口,直接在main.lua中require "websocket_main"就可以加载运行; ]] -- 加载WebSocket client数据接收功能模块 local websocket_receiver = require "websocket_receiver" -- 加载WebSocket client数据发送功能模块 local websocket_sender = require "websocket_sender" -- WebSocket服务器地址和端口 -- 这里使用的地址和端口,会不定期重启或维护,仅能用作测试用途,不可商用,说不定哪一天就关闭了 -- 用户开发项目时,替换为自己的商用服务器地址和端口 -- 加密TCP链接 wss 表示加密 local SERVER_URL = "wss://echo.airtun.air32.cn/ws/echo" -- 这是另外一个测试服务, 能响应websocket的二进制帧 --local SERVER_URL = "ws://echo.airtun.air32.cn/ws/echo2" -- websocket_main的任务名 local TASK_NAME = websocket_sender.TASK_NAME_PREFIX.."main" -- WebSocket client的事件回调函数 local function websocket_client_event_cbfunc(ws_client, event, data, fin, opcode) log.info("WebSocket事件回调", ws_client, event, data, fin, opcode) -- WebSocket连接成功 if event == "conack" then sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "CONNECT", true) -- 连接成功,通知网络环境检测看门狗功能模块进行喂狗 sys.publish("FEED_NETWORK_WATCHDOG") -- 接收到服务器下发的数据 -- data:string类型,表示接收到的数据 -- fin:number类型,1表示是最后一个数据包,0表示还有后续数据包 -- opcode:number类型,表示数据包类型(1-文本,2-二进制) elseif event == "recv" then -- 对接收到的数据处理 websocket_receiver.proc(data, fin, opcode) -- 发送成功数据 -- data:number类型,表示发送状态(通常为nil或0) elseif event == "sent" then log.info("WebSocket事件回调", "数据发送成功,发送确认") -- 发送消息通知 websocket sender task sysplus.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "SEND_OK", data) -- 服务器断开WebSocket连接 elseif event == "disconnect" then -- 发送消息通知 websocket main task sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "DISCONNECTED", false) -- 严重异常,本地会主动断开连接 -- data:string类型,表示具体的异常,有以下几种: -- "connect":tcp连接失败 -- "tx":数据发送失败 -- "other":其他异常 elseif event == "error" then if data == "connect" then -- 发送消息通知 websocket main task,连接失败 sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "CONNECT", false) elseif data == "other" or data == "tx" then -- 发送消息通知 websocket main task,出现异常 sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "ERROR") end end end -- websocket main task 的任务处理函数 local function websocket_client_main_task_func() local ws_client local result, msg while true do -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待 while not socket.adapter(socket.dft()) do log.warn("WebSocket主任务", "等待网络就绪", socket.dft()) -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY" -- 或者等待1秒超时退出阻塞等待状态; -- 注意:此处的1000毫秒超时不要修改的更长; -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡 -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配 -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft()) sys.waitUntil("IP_READY", 1000) end -- 检测到了IP_READY消息 log.info("WebSocket主任务", "收到网络就绪消息", socket.dft()) -- 清空此task绑定的消息队列中的未处理的消息 sysplus.cleanMsg(TASK_NAME) -- 创建WebSocket client对象 ws_client = websocket.create(nil, SERVER_URL) -- 如果创建WebSocket client对象失败 if not ws_client then log.error("WebSocket主任务", "WebSocket创建失败") goto EXCEPTION_PROC end -- 设置自定义请求头 --如果有需要,根据自己的实际需求,在此处配置请求头并打开注释。 --if ws_client.headers then --ws_client:headers({Auth="Basic ABCDEGG"}) --end -- 注册WebSocket client对象的事件回调函数 ws_client:on(websocket_client_event_cbfunc) -- 连接server result = ws_client:connect() -- 如果连接server失败 if not result then log.error("WebSocket主任务", "WebSocket连接失败") goto EXCEPTION_PROC end -- 连接、断开连接、异常等各种事件的处理调度逻辑 while true do -- 等待"WEBSOCKET_EVENT"消息 msg = sysplus.waitMsg(TASK_NAME, "WEBSOCKET_EVENT") log.info("WebSocket主任务等待消息", msg[2], msg[3], msg[4]) -- connect连接结果 -- msg[3]表示连接结果,true为连接成功,false为连接失败 if msg[2] == "CONNECT" then -- WebSocket连接成功 if msg[3] then log.info("WebSocket主任务", "连接成功") -- 通知websocket sender数据发送应用模块的task,WebSocket连接成功 sysplus.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "CONNECT_OK", ws_client) -- WebSocket连接失败 else log.info("WebSocket主任务", "连接失败") -- 退出循环,发起重连 break end -- 需要主动关闭WebSocket连接 -- 用户需要主动关闭WebSocket连接时,可以调用sysplus.sendMsg(TASK_NAME, "WEBSOCKET_EVENT", "CLOSE") elseif msg[2] == "CLOSE" then -- 主动断开WebSocket client连接 ws_client:disconnect() -- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间 sys.wait(1000) break -- 被动关闭了WebSocket连接 -- 被网络或者服务器断开了连接 elseif msg[2] == "DISCONNECTED" then break -- 出现了其他异常 elseif msg[2] == "ERROR" then break end end -- 出现异常 ::EXCEPTION_PROC:: -- 清空此task绑定的消息队列中的未处理的消息 sysplus.cleanMsg(TASK_NAME) -- 通知websocket sender数据发送应用模块的task,WebSocket连接已经断开 sysplus.sendMsg(websocket_sender.TASK_NAME, "WEBSOCKET_EVENT", "DISCONNECTED") -- 如果存在WebSocket client对象 if ws_client then -- 关闭WebSocket client,并且释放WebSocket client对象 ws_client:close() ws_client = nil end -- 5秒后跳转到循环体开始位置,自动发起重连(与MQTT保持一致) sys.wait(5000) end end --创建并且启动一个task sysplus.taskInitEx(websocket_client_main_task_func, TASK_NAME)