-- linksocket.lua -- 功能:管理多个 TCP Socket 连接,支持手动连接/断开,自动重连,数据收发 local log = require "log" local sys = require "sys" local socket = require "socket" -- 服务器配置 local SERVER_IP = "121.43.69.62" local SERVER_PORT = 8767 local MAX_CLIENTS = 6 -- 客户端状态表 local clients = {} local keepConnecting = {} local recvCallback = nil -- 初始化所有socket槽位 for i = 1, MAX_CLIENTS do clients[i] = { id = i, socket = nil, connected = false } keepConnecting[i] = false end -- 发送连接状态响应 local function sendConnStatus(subCmd, socketId, status) local uart = require "uart" local frame = string.char(0x55, 0xAA, 0x83, subCmd, socketId, status, 0xAA, 0x55) uart.write(1, frame) log.debug("Socket", socketId, "status response, subCmd=", subCmd, "status=", status) end -- 设置是否保持连接 local function setKeepConnecting(id, keep) if id < 1 or id > MAX_CLIENTS then return false end keepConnecting[id] = keep if not keep and clients[id].connected and clients[id].socket then clients[id].socket:close() clients[id].socket = nil clients[id].connected = false sendConnStatus(0x02, id, 0) end return true end -- 发送数据到指定socket local function sendToSocket(id, data) if id < 1 or id > MAX_CLIENTS then log.error("sendToSocket: invalid id", id) return false end if clients[id].connected and clients[id].socket then clients[id].socket:asyncSend(data) log.info("Send to socket", id, "len=", #data) return true else log.warn("Socket", id, "not connected, cannot send") return false end end -- 注册数据接收回调 local function setRecvCallback(cb) recvCallback = cb end -- 为每个socket创建常驻任务 for id = 1, MAX_CLIENTS do sys.taskInit(function() local socketId = id log.debug("Socket", socketId, "control task started") while true do while not keepConnecting[socketId] do sys.wait(1000) end while keepConnecting[socketId] do while not socket.isReady() do if not keepConnecting[socketId] then break end sys.wait(1000) end if not keepConnecting[socketId] then break end local sock = socket.tcp() log.debug("Socket", socketId, "connecting to", SERVER_IP, SERVER_PORT) local connected = false while not connected and keepConnecting[socketId] do connected = sock:connect(SERVER_IP, SERVER_PORT) if not connected then log.warn("Socket", socketId, "connect failed, retry in 3s") sys.wait(3000) end end if not keepConnecting[socketId] then if sock then sock:close() end break end clients[socketId].socket = sock clients[socketId].connected = true log.info("Socket", socketId, "connected") sendConnStatus(0x01, socketId, 0) while keepConnecting[socketId] and clients[socketId].connected do local ok = sock:asyncSelect(60, "recv") if not ok then log.warn("Socket", socketId, "connection lost") break end sys.wait(100) end if clients[socketId].socket then clients[socketId].socket:close() clients[socketId].socket = nil end clients[socketId].connected = false if not keepConnecting[socketId] then sendConnStatus(0x02, socketId, 0) break else log.info("Socket", socketId, "will reconnect after 3s") sys.wait(3000) end end end end) end -- 订阅底层Socket接收事件 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 then log.info("Socket", client.id, "received data len=", #data) if recvCallback then recvCallback(client.id, data) end end break end end end) -- 模块接口 local M = { setKeepConnecting = setKeepConnecting, sendToSocket = sendToSocket, setRecvCallback = setRecvCallback, } return M