主题
网络工具例程 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")。
验证方法:
- 电脑上用
nc -u 192.168.1.x 8001发一串字符,能收到pong:开头的回包。 - 换一个端口的客户端再发,日志里显示的发件人端口不同 —— 说明地址确实来自
recvfrom。
注意事项:
- 用
recv收 UDP 会取不到发件人(必须先connect设默认目标,那就只收得到这一个来源的包)。 - 不设
rcvtimeo时recvfrom会一直等,定时器回调会被卡住。