Skip to content

网络工具例程 5:手写 UDP 服务器(一问一答) ​

这一页只讲这一个例程。同组其余例程、以及这个库的函数说明都在 05-05-net。

适用:自定义 UDP 协议的应答服务 | 依赖模块:net timer | 难度:★★☆

场景:UDP 没有连接,靠「收到谁的包就回给谁」。用 recvfrom 拿发件人地址,再用 sendto 回包。

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

lua
local PORT = 8001

local u, e = net.socket("UDP")
if not u then
    print("建不出来:", net.errstr(e))
    return
end
if u:bind("0.0.0.0", PORT) ~= 0 then              -- 服务器必须给端口
    print("端口绑定失败", PORT)
    return
end
u:setoption("rcvtimeo", 50)      -- 收不到就 50ms 后返回,不卡主循环
print("UDP 服务器已启动:", PORT)

timer.start(100, function()
    local data, ip, port, err = u:recvfrom(256)
    if err == 0 and #data > 0 then
        print("来自", net.unpackip(ip, "*s"), port, ":", data)
        u:sendto("pong:" .. data, ip, port)   -- 回给发件人
    end
end)

要点:

  • UDP 服务器只需要 socket → bind(端口必填)→ recvfrom,没有 listen / accept。
  • 一次 recvfrom 收一个完整数据包,发件人的 ip / port 一并返回,回包原样填回去即可。
  • 发广播(如 255.255.255.255)前要先 u:setoption("broadcast")。

验证方法:

  1. 电脑上用 nc -u 192.168.1.x 8001 发一串字符,能收到 pong: 开头的回包。
  2. 换一个端口的客户端再发,日志里显示的发件人端口不同 —— 说明地址确实来自 recvfrom。

注意事项:

  • 用 recv 收 UDP 会取不到发件人(必须先 connect 设默认目标,那就只收得到这一个来源的包)。
  • 不设 rcvtimeo 时 recvfrom 会一直等,定时器回调会被卡住。

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