Lua Academy · Lesson

Building a Client

Request data from a server.

Lesson 2 of 413 steps

Building a Client is a free Lua Academy lesson on CoddyKit. This is lesson 2 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, and your progress syncs across the web and the CoddyKit app. The Lua Academy course includes 4 lessons in total.

Client Lifecycle

A TCP client follows a clear lifecycle: create a socket, connect to a server, exchange data, then close.

In LuaSocket each step is one method call, and each can fail. A well-written client checks every return value and cleans up its socket on any error path.

local socket = require("socket")
local client = assert(socket.tcp())

Connecting Safely

Set a connect timeout before calling connect so a dead host does not hang your program. A few seconds is typical.

If connect returns nil, log the error and abort. Never assume the handshake succeeded.

client:settimeout(5)
local ok, err = client:connect("127.0.0.1", 8080)
if not ok then
  client:close()
  error("connect failed: " .. err)
end

Using socket.connect

For the common case, socket.connect(host, port) wraps creation and connection. It returns a ready client object or nil and an error.

This is concise but gives you no chance to set a timeout before the handshake, so prefer the explicit form for unreliable networks.

local socket = require("socket")
local client, err = socket.connect("example.com", 13)
if not client then error(err) end

Sending a Request

Once connected, write your request bytes with send. Many text protocols delimit lines with carriage-return + newline (\r\n).

Because TCP is a stream, terminate each logical message clearly so the server knows where it ends.

local msg = "PING\r\n"
local sent, err = client:send(msg)
if not sent then error("send failed: " .. err) end

Reading a Line Reply

For line-based protocols, loop reading with the "*l" pattern. Each call returns one line without its terminator.

On nil, inspect the error: "closed" means the server hung up, while "timeout" means no data arrived in time.

client:settimeout(5)
local line, err = client:receive("*l")
if line then
  print("server said:", line)
else
  print("recv error:", err)
end

Reading a Whole Response

Request/response protocols often read everything until the server closes. Use "*a" to capture the full body.

If you half-close your send side first with shutdown("send"), the server sees end-of-input and can finish its reply.

client:send("GET DATA\r\n")
client:shutdown("send")
local body, err = client:receive("*a")
print(#(body or ""), "bytes received")

Fixed-Length Framing

Binary protocols often prefix each message with its length. Read the length header first, then read exactly that many bytes.

Passing a number to receive blocks until that count arrives or the socket errors, giving you precise framing over the byte stream.

local header = client:receive(4)
local len = string.unpack(">I4", header)
local payload = client:receive(len)

A Complete Echo Client

Here is the whole flow: connect, send a line, read the echoed line, and close. This is the canonical LuaSocket client shape.

Notice every fallible call is guarded with assert for brevity, but a real client would handle errors gracefully.

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()

Handling Disconnects

Servers can drop connections at any time. A send to a closed peer may return nil, "closed", and receive returns the partial data plus the error.

Treat "closed" as a normal terminal state, not a crash. Reconnect logic belongs in a retry wrapper around the client.

local data, err, partial = client:receive("*a")
if err == "closed" then
  print("peer closed, got", #partial, "bytes")
end

Non-Blocking Clients

Set the timeout to 0 for a fully non-blocking client. Calls then return immediately, signalling "timeout" when no progress is possible.

Combine this with socket.select to wait efficiently for readiness across many sockets without busy-looping.

client:settimeout(0)
local r = socket.select({client}, nil, 5)
if #r > 0 then print(client:receive("*l")) end

Resolving Hostnames

If you connect by hostname, LuaSocket resolves it for you. To inspect or cache the resolution, call socket.dns.toip or socket.dns.getaddrinfo yourself.

Resolving once and connecting by IP avoids repeated DNS lookups in a tight reconnect loop.

local socket = require("socket")
local ip = assert(socket.dns.toip("example.com"))
local c = assert(socket.connect(ip, 80))

Quick Check

Choose the correct way to read everything a server sends until it closes.

Recap

You built a TCP client end to end: connect with a timeout, frame and send requests, read line, byte-count, or whole-stream responses, and close cleanly.

You also saw disconnect handling, non-blocking mode with select, and DNS caching. Next you will write the server side that answers these clients.

Free to start

Learn Lua with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
40
Lessons
159

Frequently Asked Questions

Is the “Building a Client” lesson free?

Yes — any 3 lessons of the Lua Academy learning path, including “Building a Client”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Lua Academy course includes 4 lessons in total.

What will I learn in “Building a Client”?

Request data from a server. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Lua Academy?

No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 2 of 4.

How long does the “Building a Client” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Lua Academy lesson?

Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. TCP Basics
  2. Building a Client
  3. Building a Server
  4. HTTP Requests
← Back to Lua Academy