构建客户端
从服务器请求数据。
构建客户端 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。
客户端生命周期
TCP 客户端遵循清晰的生命周期:创建套接字、连接服务器、交换数据,然后关闭。
在 LuaSocket 中,每一步都是一次方法调用,而且每一步都可能失败。编写良好的客户端会检查每个返回值,并在任何错误路径上清理其套接字。
local socket = require("socket")
local client = assert(socket.tcp())安全连接
在调用 connect 之前设置连接超时,这样无响应的主机就不会让程序一直挂起。通常设置为几秒。
如果 connect 返回 nil,请记录错误并中止。切勿假设握手已经成功。
client:settimeout(5)
local ok, err = client:connect("127.0.0.1", 8080)
if not ok then
client:close()
error("connect failed: " .. err)
end使用 socket.connect
在常见情况下,socket.connect(host, port) 会封装创建和连接。它返回一个已就绪的客户端对象,或者返回 nil 和一个错误。
这种写法简洁,但您无法在握手前设置超时,因此在不可靠的网络中应优先使用显式形式。
local socket = require("socket")
local client, err = socket.connect("example.com", 13)
if not client then error(err) end发送请求
连接建立后,使用 send 写入请求字节。许多文本协议会使用回车符 + 换行符(\r\n)来分隔各行。
由于 TCP 是流,请明确终止每条逻辑消息,以便服务器知道其结束位置。
local msg = "PING\r\n"
local sent, err = client:send(msg)
if not sent then error("send failed: " .. err) end读取单行回复
对于基于行的协议,请使用 "*l" 模式循环读取。每次调用都会返回一行,不包含其终止符。
返回 nil 时,请检查错误:"closed" 表示服务器已断开连接,而 "timeout" 表示在规定时间内没有数据到达。
client:settimeout(5)
local line, err = client:receive("*l")
if line then
print("server said:", line)
else
print("recv error:", err)
end读取完整响应
请求/响应协议通常会读取所有内容,直到服务器关闭连接。使用 "*a" 可以获取完整正文。
如果先用 shutdown("send") 半关闭发送端,服务器就会看到输入结束,并能完成响应。
client:send("GET DATA\r\n")
client:shutdown("send")
local body, err = client:receive("*a")
print(#(body or ""), "bytes received")固定长度分帧
二进制协议通常会在每条消息前加上其长度。先读取长度标头,然后准确读取相应字节数。
向 receive 传入一个数字后,它会一直阻塞,直到收到指定数量的字节或套接字出错,从而在字节流上实现精确分帧。
local header = client:receive(4)
local len = string.unpack(">I4", header)
local payload = client:receive(len)完整的回显客户端
下面是完整流程:连接、发送一行、读取回显行,然后关闭。这是 LuaSocket 客户端的典型结构。
请注意,为简洁起见,每个可能失败的调用都用 assert 保护,但真正的客户端会优雅地处理错误。
local socket = require("socket")
local c = assert(socket.connect("127.0.0.1", 8080))
assert(c:send("hello\r\n"))
print(c:receive("*l"))
c:close()处理断开连接
服务器可能随时丢弃连接。向已关闭的对端执行 send 可能返回 nil, "closed",而 receive 会返回部分数据及错误。
将 "closed" 视为正常终止状态,而不是崩溃。重连逻辑应放在客户端外围的重试包装器中。
local data, err, partial = client:receive("*a")
if err == "closed" then
print("peer closed, got", #partial, "bytes")
end非阻塞客户端
将超时设置为 0,即可实现完全非阻塞的客户端。此后调用会立即返回,在无法取得进展时发出 "timeout" 信号。
将其与 socket.select 结合,以便高效等待多个套接字的就绪状态,而不进行忙等循环。
client:settimeout(0)
local r = socket.select({client}, nil, 5)
if #r > 0 then print(client:receive("*l")) end解析主机名
如果按主机名连接,LuaSocket 会为您解析。若要检查或缓存解析结果,请自行调用 socket.dns.toip 或 socket.dns.getaddrinfo。
只解析一次并通过 IP 连接,可以避免在紧密的重连循环中重复进行 DNS 查询。
local socket = require("socket")
local ip = assert(socket.dns.toip("example.com"))
local c = assert(socket.connect(ip, 80))快速检查
选择正确的方式,读取服务器发送的全部内容,直到服务器关闭连接。
回顾
您完整构建了一个 TCP 客户端:使用超时进行连接,组织并发送请求,读取按行、按字节数或整个流返回的响应,然后干净地关闭连接。
您还了解了断开连接的处理方式、使用 select 的非阻塞模式以及 DNS 缓存。接下来,您将编写能够响应这些客户端的服务器端。
常见问题解答
「构建客户端」课时是免费的吗?
是的 — 「构建客户端」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。
「构建客户端」这节课中我会学到什么?
从服务器请求数据。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Lua Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「构建客户端」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Lua Academy 课中编写并运行代码吗?
能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。