-- linksocket.lua -- 功能:管理多个 TCP Socket -- 行为:接收到连接命令后尝试连接一次 -- 连接失败 → 主动上报失败 (0x83 03) -- 连接成功 → 主动上报成功 (0x83 01) -- 中途掉线 → 主动上报断开 (0x83 02),停止,等待新连接命令 local log = require "log" local sys = require "sys" local socket = require "socket" local sim = require "sim" -- 云快充 -- local server_config = { -- ip = "121.43.69.62", -- port = 8767 -- } -- 百瑞 local server_config = { ip = "129.211.170.245", port = 9002 } -- 国网 -- local server_config = { -- ip = "121.199.29.175", -- port = 1883 -- } local MAX_CLIENTS = 6 local clients = {} local connectRequested = {} -- 收到连接命令的标志 local disconnectRequested = {} -- 收到断开命令的标志 local recvCallback = nil for i = 1, MAX_CLIENTS do clients[i] = { id = i, socket = nil, connected = false } connectRequested[i] = false disconnectRequested[i] = false end local uart local function getUart() if not uart then uart = require "uart" end return uart end -- 发送状态通知到 STM32 -- subCmd: 0x01=已连接 0x02=已断开 0x03=连接失败 local function sendStatus(subCmd, socketId, status) local frame = string.char(0x55, 0xAA, 0x83, subCmd, socketId, status or 0, 0xAA, 0x55) getUart().write(1, frame) log.info("Socket", socketId, subCmd == 0x01 and "connected" or subCmd == 0x02 and "disconnected" or "connect_failed", "status=", status or 0) end -- 关闭单个socket local function closeSocket(id) if clients[id].socket then clients[id].socket:close() clients[id].socket = nil end clients[id].connected = false connectRequested[id] = false disconnectRequested[id] = false end -- ── 外部接口 ────────────────────────────────────────── -- STM32 要求连接 local function connectSocket(id) if id < 1 or id > MAX_CLIENTS then log.error("connectSocket: invalid id", id) return false end if clients[id].connected then log.info("Socket", id, "already connected") sendStatus(0x01, id, 0) return true end connectRequested[id] = true disconnectRequested[id] = false return true end -- STM32 要求断开 local function disconnectSocket(id) if id < 1 or id > MAX_CLIENTS then log.error("disconnectSocket: invalid id", id) return false end connectRequested[id] = false disconnectRequested[id] = true if clients[id].connected then closeSocket(id) sendStatus(0x02, id, 0) end return true end -- 发送数据 local function sendToSocket(id, data) if id < 1 or id > MAX_CLIENTS then return false end if clients[id].connected and clients[id].socket then clients[id].socket:asyncSend(data) return true end return false end local function setRecvCallback(cb) recvCallback = cb end local function setServerAddress(ip, port) if not ip or #ip == 0 or not port or port <= 0 or port > 65535 then return false end log.info("setServerAddress:", ip, port) server_config.ip = ip server_config.port = port for id = 1, MAX_CLIENTS do if clients[id].connected then closeSocket(id) sendStatus(0x02, id, 0) end end return true end local function getLinkStatus() local status = {} for i = 1, MAX_CLIENTS do status[i] = clients[i].connected end return status end -- ── 每个Socket的控制任务 ───────────────────────────── for id = 1, MAX_CLIENTS do sys.taskInit(function() local socketId = id while true do -- 等待连接命令 while not connectRequested[socketId] do sys.wait(500) end -- 用 do..break 代替 goto,确保失败/断开都回到外层循环顶部 repeat disconnectRequested[socketId] = false -- 等待网络就绪且SIM卡正常 while not socket.isReady() or not sim.getStatus() do if disconnectRequested[socketId] then break end local simStatus = sim.getStatus() if not simStatus then log.warn("Socket", socketId, "waiting for SIM card, status:", simStatus) end sys.wait(1000) end if disconnectRequested[socketId] then connectRequested[socketId] = false break end -- 再次检查SIM卡状态,防止等待期间SIM卡被拔出 if not sim.getStatus() then connectRequested[socketId] = false sendStatus(0x03, socketId, 2) log.warn("Socket", socketId, "connect failed: SIM card not ready") break end -- 尝试连接(只试一次) local sock = socket.tcp() log.info("Socket", socketId, "connecting to", server_config.ip, server_config.port) local ok = sock:connect(server_config.ip, server_config.port) if disconnectRequested[socketId] or not ok then if sock then sock:close() end connectRequested[socketId] = false sendStatus(0x03, socketId, 1) log.warn("Socket", socketId, "connect failed") break end -- 连接成功 clients[socketId].socket = sock clients[socketId].connected = true connectRequested[socketId] = false sendStatus(0x01, socketId, 0) log.info("Socket", socketId, "connected") -- 监控连接,直到掉线或收到断开命令 while clients[socketId].connected and not disconnectRequested[socketId] do -- 检查SIM卡状态,如果SIM卡被拔出则断开连接 if not sim.getStatus() then log.warn("Socket", socketId, "SIM card removed, disconnecting") break end local alive = sock:asyncSelect(60, "recv") if not alive then log.warn("Socket", socketId, "connection lost") break end sys.wait(100) end until true -- 如果还在连接状态说明出了循环 = 掉线或断开 if clients[socketId].connected then closeSocket(socketId) sendStatus(0x02, socketId, 0) log.info("Socket", socketId, "disconnected, waiting reconnect cmd") end end end) end -- 监听SIM卡状态变化,SIM卡被拔出时断开所有连接 sys.subscribe("SIM_IND", function(para) log.info("SIM_IND received:", para) -- SIM卡未就绪(被拔出或异常) if para ~= "RDY" then for id = 1, MAX_CLIENTS do if clients[id].connected then log.warn("SIM card removed, disconnecting socket", id) closeSocket(id) sendStatus(0x02, id, 3) -- 状态码3表示SIM卡异常导致断开 end end end end) -- 数据接收 sys.subscribe("SOCKET_RECV", function(socketId) for i, client in ipairs(clients) do if client.socket and client.socket.id == socketId and client.connected then local data = client.socket:asyncRecv() if data and #data > 0 and recvCallback then recvCallback(client.id, data) end break end end end) local M = { connectSocket = connectSocket, disconnectSocket = disconnectSocket, sendToSocket = sendToSocket, setRecvCallback = setRecvCallback, setServerAddress = setServerAddress, getLinkStatus = getLinkStatus, } return M