network 模块 编程使用说明
本网络模块支持:HTTP / TCP / UDP / MQTT 服务器,以及一个带自动重连的 MQTT 客户端。
local network = require("network")
1. 总览
模块级函数(用 network.xxx 调用)
| 函数 | 作用 | 返回 |
|---|---|---|
network.create(port, cb) | 创建基础 HTTP 服务(旧接口) | 句柄对象 |
network.start_http_server(port, cb) | 启动 HTTP / WebSocket 服务器 | 句柄对象 |
network.start_tcp_server(port, cb) | 启动 TCP 服务器 | 句柄对象 |
network.start_udp_server(port, cb) | 启动 UDP 服务器 | 句柄对象 |
network.start_mqtt_server(port, cb) | 启动 MQTT Broker(服务端) | 句柄对象 |
network.start_mqtt_cli(host, user, pass, port, id, will_topic, will_msg, cb) | 启动 MQTT 客户端(自动重连) | 句柄对象 |
句柄方法(用 handle:xxx() 调用)
上面每个函数都返回一个句柄对象,可调用下列方法:
| 方法 | 适用 | 作用 |
|---|---|---|
handle:poll(timeout_ms) | 全部 | 驱动一次事件循环,必须在主循环里反复调用 |
handle:free() | 全部 | 关闭连接、释放定时器与资源(见"生命周期") |
handle:send(data, len) | 服务器 | 向该服务器所有已连接客户端广播数据 |
handle:readfile(path) | 全部 | 读取一个文件,返回内容字符串(失败返回 nil) |
handle:mqttc_pub(topic, payload [, qos]) | MQTT 客户端 | 发布消息,返回 bool 表示是否发出 |
handle:mqttc_sub(topic [, qos]) | MQTT 客户端 | 订阅主题,返回 bool 表示是否发出 |
handle:mqttc_connected() | MQTT 客户端 | 是否已连接并就绪(收到 CONNACK) |
handle:mqttc_ping() | MQTT 客户端 | 发送 PING,返回 bool 表示是否发出 |
重要:所有服务/客户端都靠handle:poll()驱动。创建句柄后,必须在你的主循环里
周期性调用poll,否则不会有任何网络活动、回调也不会触发。
2. 主循环范式
所有例子都遵循同一个骨架:创建句柄 → 循环 poll → 退出时 free。
local network = require("network")
local srv = network.start_tcp_server(9000, function(req)
-- 处理逻辑,见后文
return "ok"
end)
-- 主循环
while running do
srv:poll(100) -- 每次最多阻塞 100ms 处理事件
end
srv:free() -- 退出时释放poll(timeout_ms) 的 timeout_ms 是本次事件处理的最长等待毫秒数。常用 10~100ms。
3. HTTP / WebSocket 服务器
创建
local http = network.start_http_server(port, callback)port:监听端口(数字),内部监听http://0.0.0.0:<port>。callback(req):每次收到 HTTP 请求或 WebSocket 消息时调用,返回值作为响应体。
回调收到的 req 表
HTTP 请求时:
| 字段 | 说明 |
|---|---|
req.is_http | true |
req.url | 请求 URI(路径部分) |
req.method | 请求方法,如 "GET" / "POST" |
req.query | 查询字符串(URL 里 ? 后面的部分) |
req.data | 同 query(当前实现二者相同) |
WebSocket 消息时:
| 字段 | 说明 |
|---|---|
req.is_ws | true |
req.data | 客户端发来的消息内容 |
回调返回的字符串:HTTP 情况下作为 200 响应正文返回;WebSocket 情况下作为文本帧回发给该客户端。返回空串时 HTTP 会回一个空白页。
内置路由说明
/ws:WebSocket 升级端点。客户端连到ws://<ip>:<port>/ws即可建立 WebSocket。/admin/*:内置静态文件服务,根目录为/admin/,带一周缓存。这类请求不会进入你的回调.- 其余路径:进入你的回调。
例子
local network = require("network")
local http = network.start_http_server(8080, function(req)
if req.is_ws then
-- WebSocket:回声
return "echo: " .. req.data
end
-- 普通 HTTP
if req.url == "/hello" then
return "<h1>Hello from SimFAS</h1>"
elseif req.url == "/api/status" then
return '{"status":"ok"}'
end
return "<html><body>path=" .. req.url ..
" method=" .. req.method .. "</body></html>"
end)
while true do
http:poll(50)
end主动向所有已连接的 WebSocket / HTTP 长连接广播(例如推送):
http:send("push message", #("push message"))4. TCP 服务器
创建
local tcp = network.start_tcp_server(port, callback)port:监听端口,内部监听tcp://0.0.0.0:<port>。callback(req):收到数据时调用。req.data为收到的字节;返回的字符串会被发回给该连接。
回调收到的 req 表
| 字段 | 说明 |
|---|---|
req.data | 本次收到的数据(当前实现为该连接接收缓冲的全部内容) |
注意:req.data是接收缓冲里的累积数据。若你的协议有粘包/分包,需要在用户脚本自行按协议
切分。回调结束后接收缓冲会被清空。
例子
local network = require("network")
local tcp = network.start_tcp_server(9000, function(req)
print("recv:", req.data)
-- 简单回声
return "ACK:" .. req.data
end)
while true do
tcp:poll(50)
end向所有 TCP 客户端广播:
local msg = "broadcast\n"
tcp:send(msg, #msg)5. UDP 服务器
创建
local udp = network.start_udp_server(port, callback)port:监听端口,内部监听udp://0.0.0.0:<port>。callback(req):收到数据报时调用。req.data为该数据报内容;返回字符串会回发给来源地址。
回调收到的 req 表
| 字段 | 说明 |
|---|---|
req.data | 本次收到的数据报内容 |
例子
local network = require("network")
local udp = network.start_udp_server(9001, function(req)
print("udp recv:", req.data)
return "pong"
end)
while true do
udp:poll(50)
end6. MQTT 服务器(Broker)
创建
local broker = network.start_mqtt_server(port, callback)port:监听端口,内部监听mqtt://0.0.0.0:<port>。callback(msg):当有客户端 PUBLISH 消息时调用(消息已自动转发给订阅方,回调用于你旁路观察/记录)。
内部已实现基本的 SUBSCRIBE 管理、PUBLISH 按主题匹配转发、PINGREQ/PINGRESP 心跳。
回调收到的 msg 表
| 字段 | 说明 |
|---|---|
msg.topic | 发布的主题 |
msg.data | 发布的消息内容 |
例子
local network = require("network")
local broker = network.start_mqtt_server(1883, function(msg)
print(string.format("[broker] %s -> %s", msg.topic, msg.data))
-- 这里的返回值不会作为 MQTT 响应,仅回调
end)
while true do
broker:poll(50)
end7. MQTT 客户端(带自动重连)
这是本模块功能最完整、最需要注意用法的部分。客户端内部有一个 5 秒重连定时器:
连接断开后会自动尝试重连,无需你手动处理。
创建
local mqttc = network.start_mqtt_cli(
host, -- 1) broker 主机名/IP,字符串
user, -- 2) 用户名,字符串(无则传 "")
pass, -- 3) 密码,字符串(无则传 "")
port, -- 4) broker 端口,数字,如 1883
client_id, -- 5) 客户端 ID,字符串
will_topic, -- 6) 遗嘱主题,字符串(无则传 "")
will_message, -- 7) 遗嘱消息,字符串(无则传 "")
callback -- 8) 事件回调函数
)八个参数全部必填不用的字符串
参数请传空串"",不要省略。连接使用clean session = true,遗嘱 QoS 为 0。
回调收到的 ev 表
回调按连接状态变化和消息到达触发,ev.event 是事件类型字符串:
ev.event | 触发时机 | 额外字段 |
|---|---|---|
"open" | 已连接并收到 CONNACK,此后才可收发 | — |
"message" | 收到订阅的消息 | ev.topic, ev.data |
"close" | 连接关闭(之后会自动重连) | — |
"error" | 连接出错 | — |
"connect" | 底层 TCP 连接事件 | — |
"timer" | 5 秒重连定时器触发且当前已连接时 | — |
收发方法
| 方法 | 返回 | 说明 |
|---|---|---|
mqttc:mqttc_connected() | bool | 是否已就绪(连接存在且收到 CONNACK) |
mqttc:mqttc_sub(topic [, qos]) | bool | 订阅;qos 可选(0~3,默认 1) |
mqttc:mqttc_pub(topic, payload [, qos]) | bool | 发布;qos 可选(0~3,默认 1) |
mqttc:mqttc_ping() | bool | 发送 PING |
关键防呆:
mqttc_pub/mqttc_sub/mqttc_ping在**未连接或未就绪时会直接返回false而不发送**,不会崩溃。因此:
- 不要在连上之前每秒盲发。正确做法是收到
"open"事件后再订阅/发布。- 每次调用都应检查返回值,
false表示这次没发出去(连接还没就绪)。- 订阅是幂等动作:在每次收到
"open"时重新订阅即可,不需要定时轮询式地 sub。
完整例子
local network = require("network")
local mqttc -- 前置声明,便于回调里引用
mqttc = network.start_mqtt_cli(
"broker.example.com", -- host
"myuser", -- user
"mypass", -- pass
1883, -- port
"sim-client-001", -- client id
"clients/001/will", -- will topic
"offline", -- will message
function(ev)
if ev.event == "open" then
print("MQTT connected, subscribing...")
-- 连接就绪后订阅(重连后会再次收到 open,自动重订阅)
mqttc:mqttc_sub("cmd/led", 1)
mqttc:mqttc_sub("cmd/relay", 1)
elseif ev.event == "message" then
print(string.format("MSG %s = %s", ev.topic, ev.data))
-- 举例:根据主题处理
if ev.topic == "cmd/led" then
-- do something with ev.data
end
elseif ev.event == "close" then
print("MQTT disconnected (will auto-reconnect in 5s)")
elseif ev.event == "error" then
print("MQTT error")
end
end
)
-- 主循环
local counter = 0
while true do
mqttc:poll(100)
-- 周期性发布,注意判断是否就绪 / 检查返回值
counter = counter + 1
if counter % 10 == 0 then -- 大约每 1 秒(poll 100ms)
if mqttc:mqttc_connected() then
local ok = mqttc:mqttc_pub("telemetry/temp", "25.3", 0)
if not ok then
print("publish skipped: not ready")
end
end
end
end
-- mqttc:free() -- 退出前调用8. 通用方法
handle:send(data, len)
向该句柄管理的所有连接广播:WebSocket 连接以文本帧发送,其余连接以原始字节发送。
常用于 HTTP/WebSocket 服务器主动推送、TCP 服务器群发。
local payload = "hello all"
http:send(payload, #payload)handle:readfile(path)
读取文件内容,成功返回字符串,失败返回 nil。
local content = http:readfile("/etc/config.json")
if content then
print(content)
end9. 生命周期与释放
- 定时器与连接:MQTT 客户端内部的 5 秒重连定时器,以及所有连接,都由句柄持有。
调用handle:free()(或对象被 回收触发__gc)时,会一并关闭连接、释放定时器,
不会泄漏。 - 立即停止:若依赖 GC 自动回收,定时器和连接要等到该对象被 GC 才释放,在此之前
重连定时器仍在运行、仍会尝试连接。想立刻停掉,请显式调用handle:free()。 free()可安全多次调用(内部有防二次释放保护),但释放后不要再对该句柄调用任何方法。
mqttc:free() -- 立即断开、停止重连、释放资源10. 常见注意事项
- 必须持续
poll:没有poll就没有网络活动。把它放进你的主循环。 - MQTT 发送先判就绪:未连上时
pub/sub/ping返回false且不发送,别把它当成功。 - 订阅放在
"open"回调里:重连后会再次收到"open",在那里重订阅最稳,不要定时盲发 sub。 - 回调里持有句柄:如例子所示,先
local mqttc前置声明,再赋值,回调里就能引用到它。 - 字符串参数别省略:
start_mqtt_cli的用户名/密码/遗嘱等即使不用也要传""。 send是广播:它发给该句柄下所有连接,不是发给单个客户端。
最后一次更新于2026-08-12



0 条评论