160 lines
4.8 KiB
Lua
160 lines
4.8 KiB
Lua
-- 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 |