Lua Academy · บทเรียน

สร้างเซิร์ฟเวอร์

ยอมรับการเชื่อมต่อขาเข้า

บทเรียน 3 จาก 413 ขั้นตอน

สร้างเซิร์ฟเวอร์ เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

วงจรการทำงานของเซิร์ฟเวอร์

เซิร์ฟเวอร์ TCP จะ bind กับที่อยู่ รอรับการเชื่อมต่อ แล้ววนลูปรับและให้บริการไคลเอ็นต์

ใน LuaSocket คุณสร้างซ็อกเก็ตหลักด้วย socket.tcp() เปลี่ยนให้เป็นเซิร์ฟเวอร์ที่รอรับการเชื่อมต่อด้วย bind/listen แล้วดึงไคลเอ็นต์ออกจากคิวด้วย accept

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

การ bind กับพอร์ต

server:bind(host, port) จะจองที่อยู่ภายในเครื่อง ใช้ "*" หรือ "0.0.0.0" เพื่อรับการเชื่อมต่อจากทุกอินเทอร์เฟซ หรือใช้ "127.0.0.1" เพื่อรับเฉพาะการเชื่อมต่อภายในเครื่อง

การ bind จะล้มเหลวด้วย "address already in use" หากกระบวนการอื่นกำลังใช้พอร์ตนั้นอยู่

server:setoption("reuseaddr", true)
local ok, err = server:bind("*", 8080)
if not ok then error("bind failed: " .. err) end

การรอรับไคลเอ็นต์

server:listen(backlog) จะทำเครื่องหมายซ็อกเก็ตให้อยู่ในโหมดรอรับและเริ่มจัดคิวการจับมือเชื่อมต่อขาเข้า backlog คือจำนวนสูงสุดของการเชื่อมต่อที่รออยู่

ทางลัด socket.bind(host, port, backlog) จะทำการ bind และ listen ในการเรียกใช้ครั้งเดียว แล้วคืนออบเจ็กต์เซิร์ฟเวอร์ที่พร้อมใช้งาน

local socket = require("socket")
local server = assert(socket.bind("*", 8080, 32))
print("listening on", server:getsockname())

การรับการเชื่อมต่อ

server:accept() จะรอจนกว่าไคลเอ็นต์จะเชื่อมต่อ จากนั้นคืนออบเจ็กต์ไคลเอ็นต์ TCP ใหม่สำหรับคู่เชื่อมต่อนั้น ส่วนซ็อกเก็ตเซิร์ฟเวอร์เองยังคงรอรับการเชื่อมต่อ

บนซ็อกเก็ตเซิร์ฟเวอร์ที่ตั้งระยะหมดเวลาไว้ accept จะคืนค่า nil, "timeout" ทำให้คุณสลับไปทำงานอื่นได้

local client, err = server:accept()
if client then
  print("client from", client:getpeername())
end

การให้บริการไคลเอ็นต์หนึ่งราย

หลังรับการเชื่อมต่อแล้ว ให้ปฏิบัติต่อออบเจ็กต์ที่คืนค่ามาเหมือนซ็อกเก็ตไคลเอ็นต์ทุกประการ: รับคำขอด้วย receive และส่งการตอบกลับด้วย send

กำหนดระยะหมดเวลาให้ซ็อกเก็ตของไคลเอ็นต์แต่ละราย เพื่อไม่ให้ไคลเอ็นต์ที่ช้ารายเดียวทำให้เซิร์ฟเวอร์ทั้งหมดหยุดรอ

client:settimeout(10)
local line = client:receive("*l")
if line then client:send(line .. "\n") end
client:close()

ลูปรอรับการเชื่อมต่อ

เซิร์ฟเวอร์แบบวนซ้ำมาตรฐานจะทำงานเป็นลูปไม่สิ้นสุด: รับไคลเอ็นต์ ให้บริการ ปิดการเชื่อมต่อ แล้วทำซ้ำ วิธีนี้จัดการไคลเอ็นต์ได้ครั้งละหนึ่งราย

วิธีนี้เรียบง่ายและถูกต้อง แต่ไม่สามารถให้บริการไคลเอ็นต์พร้อมกันได้ เพราะคำขอที่ช้าจะขัดขวางทุกคำขอที่อยู่ถัดไป

while true do
  local c = server:accept()
  if c then
    local msg = c:receive("*l")
    if msg then c:send(msg .. "\r\n") end
    c:close()
  end
end

เซิร์ฟเวอร์สะท้อนกลับแบบพื้นฐาน

เมื่อนำทุกอย่างมารวมกัน เซิร์ฟเวอร์สะท้อนกลับจะ bind รอรับการเชื่อมต่อ แล้ววนลูปสะท้อนบรรทัดแรกของไคลเอ็นต์แต่ละรายกลับไป

นี่คือเซิร์ฟเวอร์ LuaSocket ที่สมบูรณ์และมีขนาดเล็กที่สุด อีกทั้งยังเป็นเป้าหมายที่เหมาะสำหรับไคลเอ็นต์ที่คุณสร้างไว้ก่อนหน้านี้

local socket = require("socket")
local s = assert(socket.bind("*", 8080))
while true do
  local c = s:accept()
  c:send((c:receive("*l") or "") .. "\r\n")
  c:close()
end

การทำงานพร้อมกันด้วย select

หากต้องการให้บริการไคลเอ็นต์จำนวนมากพร้อมกันโดยไม่ใช้เธรด ให้ใช้ socket.select ฟังก์ชันนี้จะคืนซ็อกเก็ตที่พร้อมอ่าน รวมถึงซ็อกเก็ตเซิร์ฟเวอร์ที่รอรับเมื่อมีไคลเอ็นต์ใหม่รออยู่

คุณจัดการ table ของไคลเอ็นต์ที่กำลังทำงานและประมวลผลเฉพาะไคลเอ็นต์ที่มีข้อมูล ทำให้ลูปเหตุการณ์แบบเธรดเดียวตอบสนองได้ดี

local readable = socket.select(watch, nil, 1)
for _, sock in ipairs(readable) do
  if sock == server then
    table.insert(watch, server:accept())
  end
end

การรับการเชื่อมต่อแบบไม่บล็อก

ตั้งค่า server:settimeout(0) เพื่อไม่ให้การรับการเชื่อมต่อบล็อก จับคู่กับ select เพื่อเรียกใช้การรับการเชื่อมต่อเฉพาะเมื่อซ็อกเก็ตที่รอรับพร้อมอ่านจริง ๆ

นี่คือรากฐานของเซิร์ฟเวอร์กระบวนการเดียวที่ปรับขนาดได้และจัดการการเชื่อมต่อหลายร้อยรายการพร้อมกัน

server:settimeout(0)
local ready = socket.select({server}, nil, 5)
if #ready > 0 then
  local c = server:accept()
end

การจัดการข้อผิดพลาดของไคลเอ็นต์

ไคลเอ็นต์อาจตัดการเชื่อมต่อกะทันหัน เมื่อ receive คืนค่า nil, "closed" หรือบัฟเฟอร์บางส่วน ให้นำไคลเอ็นต์นั้นออกจาก table ที่ใช้เฝ้าดูและปิดซ็อกเก็ตของไคลเอ็นต์

อย่าปล่อยให้การเชื่อมต่อที่เสียหายเพียงรายการเดียวทำให้ลูปรอรับหยุดทำงาน ให้แยกการล้มเหลวของไคลเอ็นต์แต่ละรายออกจากกัน

local data, err = client:receive("*l")
if err == "closed" then
  client:close()
  remove_from_watch(client)
end

การปิดระบบอย่างเรียบร้อย

เมื่อปิดระบบ ให้หยุดรับการเชื่อมต่อ ปิดซ็อกเก็ตไคลเอ็นต์ที่กำลังทำงานทุกตัว จากนั้นปิดเซิร์ฟเวอร์ที่รอรับการเชื่อมต่อเพื่อคืนพอร์ต

การตั้งค่า reuseaddr ขณะ bind ช่วยให้คุณเริ่มต้นใหม่ได้ทันทีโดยไม่ต้องรอให้ช่วงเวลา TCP TIME_WAIT สิ้นสุด

for _, c in ipairs(clients) do c:close() end
server:close()
print("server stopped")

ตรวจสอบอย่างรวดเร็ว

เลือกชุดลำดับการเรียกใช้ที่เปลี่ยนซ็อกเก็ตหลักใหม่ให้เป็นซ็อกเก็ตที่พร้อมรอรับการเชื่อมต่อ

สรุปทบทวน

คุณสร้างเซิร์ฟเวอร์ TCP: bind ด้วย reuseaddr รอรับการเชื่อมต่อด้วย backlog และวนลูปเรียกใช้ accept เพื่อให้บริการไคลเอ็นต์

คุณได้เห็นลูปแบบวนซ้ำอย่างง่าย จากนั้นจึงปรับขนาดด้วย socket.select เพื่อให้ทำงานพร้อมกันแบบไม่บล็อก รวมถึงการแยกการจัดการข้อผิดพลาดและการปิดระบบอย่างเรียบร้อย ต่อไปคุณจะเลื่อนขึ้นไปทำงานกับ HTTP

เริ่มต้นได้ฟรี

เรียนรู้ Lua ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
40
บทเรียน
159

คำถามที่พบบ่อย

บทเรียน “สร้างเซิร์ฟเวอร์” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “สร้างเซิร์ฟเวอร์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “สร้างเซิร์ฟเวอร์”

ยอมรับการเชื่อมต่อขาเข้า คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “สร้างเซิร์ฟเวอร์” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม

ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน TCP
  2. สร้างไคลเอนต์
  3. สร้างเซิร์ฟเวอร์
  4. คำขอ HTTP
← กลับไปที่ Lua Academy