Skip to content

tcp_client — TCP 客户端 ​

模块名:tcp_client

主动连接远端 TCP 服务器并收发数据。start 之后内部线程负责连接与断线重连,脚本只管在回调里处理数据。多网卡机型可以指定出口网卡。

对象方法用冒号写法即可(c:send(...)),库表里也注册了同名函数,tcp_client.send(c, ...) 等价。

TCP 客户端 vs 服务器:谁先发起连接决定组网方案

函数总览 ​

库级函数 ​

函数作用
tcp_client.creat(ip, port, [ip_self])创建客户端对象

对象方法 ​

方法作用
c:reg注册事件回调
c:start启动连接线程(自动重连)
c:send发送数据
c:set_timeout设置接收超时
c:is_linked查询连接状态
c:close关闭连接并释放线程
c:set_transparent把该连接置为串口透传通道

常量 ​

常量回调入参说明
tcp_client.CONNECTED(sock)连接建立
tcp_client.DISCONNECTED(sock)连接断开
tcp_client.RECVDATA(data, sock)收到数据。注意 data 在前、sock 在后

tcp_client.creat ​

lua
tcp_client.creat(ip, port, [ip_self]) --> client

创建 TCP 客户端对象。只创建不连接,要调 start 才开始连。

参数

#参数类型必填默认值说明
1ipstring是—服务器地址
2portinteger是—服务器端口
3ip_selfstring否""出口网卡的本地 IP,多网卡时用来强制走某块网卡

返回值

类型说明
userdata客户端对象。必须用变量长期持有,被 GC 回收会断开

示例

lua
tcpc = tcp_client.creat("192.168.1.100", 8080)

c:reg ​

lua
c:reg(event, callback)

注册事件回调。要在 start 之前注册好。

参数

#参数类型必填默认值说明
1eventinteger是—tcp_client.CONNECTED / DISCONNECTED / RECVDATA
2callbackfunction是—回调函数。类型不是 function 会直接报错

返回值

无返回值。

示例

lua
tcpc:reg(tcp_client.CONNECTED, function(sock)
    print("已连接,socket =", sock)
end)

tcpc:reg(tcp_client.RECVDATA, function(data, sock)
    print("收到", #data, "字节")
end)

tcpc:reg(tcp_client.DISCONNECTED, function(sock)
    print("连接断开,将自动重连")
end)

说明

  • 每种事件只保留最后一次注册的回调。
  • 回调在 Lua 主循环里执行,不要做长阻塞操作。

c:start ​

lua
c:start()

启动连接线程。本函数立即返回,连接建立在后台完成;断线后会自动重连。

参数

无参数(冒号语法自动传入对象)。

返回值

无返回值。


c:send ​

lua
c:send(data) --> integer

发送数据。

参数

#参数类型必填默认值说明
1datastring是—要发送的数据,可为二进制

返回值

类型说明
integer实际发送的字节数。传空串时直接返回 0,不调用底层

示例

lua
local n = tcpc:send("\x01\x03\x00\x00\x00\x0A")

c:set_timeout ​

lua
c:set_timeout(ms)

设置底层 socket 的接收超时。

参数

#参数类型必填默认值说明
1msinteger是—超时毫秒数

返回值

无返回值。


c:is_linked ​

lua
c:is_linked() --> integer

查询连接状态。

参数

无参数。

返回值

类型说明
integer1 已连接,0 未连接。是整数,不是 boolean

说明

  • 判断连接必须写 == 1。直接 if c:is_linked() then 在未连接时也成立。

c:close ​

lua
c:close()

关闭 socket 并释放连接线程。

参数

无参数。

返回值

无返回值。

说明

  • 关闭后需要重新 start 才会再次连接。

c:set_transparent ​

lua
c:set_transparent()

把这条 TCP 连接置为串口透传通道,此后串口收到的数据会直接从这条连接发出、连接收到的数据直接送到串口。

参数

无参数。

返回值

无返回值。

说明


例程 ​

每个例程都是可直接下载运行的完整脚本:注册完回调与定时器后脚本就结束,固件自动进入消息泵。 API 只用本页已文档化的函数;统一模板「场景 / 完整代码 / 要点 / 验证方法 / 注意事项」。

例程 1:连后端服务器,登录握手 + 心跳保活 + 在线状态 ​

适用:LP3201 / LP3202 / LP3203 / LP3222 / LP3232 / LP3288 / 软PLC模拟器 | 依赖模块:tcp_client timer plc | 难度:★☆☆

场景:设备主动连上位采集服务,连上先发一行登录,之后每 3 秒发一条心跳并带上温度;网络断了不用管 —— 内部线程会自动重连,重成功后要在 CONNECTED 回调里重新登录(很多现场协议在重连后必须重新注册,不然服务端当它没上线)。连接状态镜像到 M110,给梯形图/触摸屏当指示灯。

完整代码(可直接下载运行):

lua
-- 登录握手 + 心跳保活 + 在线状态镜像;断线自动重连后重新登录
tcpc = tcp_client.creat("192.168.1.100", 8080)      -- 必须长期持有(全局)
tcpc:set_timeout(3000)
plc.m(110, 0)

tcpc:reg(tcp_client.CONNECTED, function()
    plc.m(110, 1)
    tcpc:send("LOGIN " .. plc.plc_name() .. "\n")   -- 每次(重)连都要重新登录
    print("已连接后端")
end)

tcpc:reg(tcp_client.DISCONNECTED, function()
    plc.m(110, 0)
    print("已断开,等待自动重连")
end)

tcpc:reg(tcp_client.RECVDATA, function(data)
    local v = tonumber(data:match("^SET (%d+)"))    -- 服务端下发 "SET 1234"
    if v then
        plc.d(200, v)
        print("设定值写入 D200 =", v)
    end
end)

tcpc:start()                                        -- 立即返回,后台负责连接与重连

timer.start(3000, function()
    if tcpc:is_linked() == 1 then                   -- is_linked 返回整数,必须 == 1
        tcpc:send(string.format("T=%.2f\n", plc.df(100)))
    end
end)

要点:

  • start() 之后不再需要自己写重连逻辑,但应用层登录/注册必须在 CONNECTED 回调里重做,否则重连后服务端不认。
  • is_linked() 返回整数,== 1 才是真的连着;直接 if tcpc:is_linked() then 永远成立。
  • 心跳周期别小于 1000ms:回调都在同一个线程里串行执行,太密会挤掉别的活(定时器最小周期 10ms 是技术下限,不代表适合业务)。
  • tcpc 用全局变量:对象被 GC 回收,连接随之断开,表现为「跑一阵子就不动了」。
  • RECVDATA 的参数顺序是 (data, sock),只关心内容时写单参即可,别按 (sock, data) 去解。

验证方法:

  1. PC 上起一个 TCP 服务端(例如 ncat -l 8080)当"后端"。
  2. 下载脚本并重启设备:服务端应收到 LOGIN <设备名> 一行,之后每 3 秒一条 T=25.30。
  3. 上位机「在线监视」里 M110 为 ON。
  4. 服务端发一行 SET 1234:设备日志打印 设定值写入 D200 = 1234,D200 变成 1234。
  5. 直接关掉服务端再重开:日志出现「已断开」→「已连接后端」,且第二次也能收到 LOGIN(证明重登录后仍然可用)。

注意事项:

  • 以为「TCP 自动重连 = 什么都不用做」:应用层会话(登录、订阅、注册)必须自己在 CONNECTED 里重新建立。
  • send 返回的是实际发出字节数,成功发送不等于对方收到;需要确认的应用层应答要自己在 RECVDATA 里处理。
  • 别用 while true do system.sleep(3000) ... end 做心跳:sleep 不泵消息队列,会让 RECVDATA 回调永不触发。

其余例程(各自一页) ​

注意事项 ​

  • RECVDATA 回调的参数顺序是 (data, sock),不是 (sock, data)。
  • is_linked 返回整数,判断连接必须 == 1。
  • 客户端对象要长期持有(全局变量或模块级 local),否则被 GC 后连接断开。
  • TCP 是字节流,一次 RECVDATA 收到的不一定是完整的一帧。自定义协议要自己做分帧(长度前缀或分隔符)。

LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研