Budowanie serwera
Zaakceptuje Pan/Pani przychodzące połączenia.
Budowanie serwera to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.
Cykl życia serwera
Serwer TCP wiąże gniazdo z adresem, nasłuchuje połączeń, a następnie w pętli akceptuje klientów i obsługuje ich żądania.
W LuaSocket należy utworzyć obiekt nadrzędny za pomocą socket.tcp(), przekształcić go w serwer nasłuchujący za pomocą bind/listen, a następnie pobierać klientów z kolejki za pomocą accept.
local socket = require("socket")
local server = assert(socket.tcp())Przypisywanie portu
server:bind(host, port) rezerwuje lokalny adres. Należy użyć "*" lub "0.0.0.0", aby akceptować połączenia na wszystkich interfejsach, albo "127.0.0.1", aby zezwolić wyłącznie na połączenia lokalne.
Wywołanie bind kończy się błędem "address already in use", jeśli inny proces zajmuje ten port.
server:setoption("reuseaddr", true)
local ok, err = server:bind("*", 8080)
if not ok then error("bind failed: " .. err) endNasłuchiwanie klientów
server:listen(backlog) ustawia gniazdo w trybie pasywnym i zaczyna umieszczać przychodzące uzgodnienia w kolejce. backlog oznacza maksymalną liczbę oczekujących połączeń.
Skrót socket.bind(host, port, backlog) wykonuje przypisanie adresu i rozpoczęcie nasłuchiwania w jednym wywołaniu, zwracając gotowy obiekt serwera.
local socket = require("socket")
local server = assert(socket.bind("*", 8080, 32))
print("listening on", server:getsockname())Akceptowanie połączenia
server:accept() blokuje działanie do chwili połączenia klienta, a następnie zwraca zupełnie nowy obiekt klienta TCP dla tej drugiej strony. Samo gniazdo serwera nadal nasłuchuje.
W przypadku gniazda serwera z ustawionym limitem czasu accept zwraca nil, "timeout", co pozwala wykonywać w międzyczasie inne zadania.
local client, err = server:accept()
if client then
print("client from", client:getpeername())
endObsługa jednego klienta
Po wywołaniu accept zwrócony obiekt należy traktować dokładnie tak jak gniazdo klienta: odbierać żądania za pomocą receive i wysyłać odpowiedzi za pomocą send.
Dla gniazda każdego klienta należy ustawić osobny limit czasu, aby jeden powolny klient nie zablokował całego serwera.
client:settimeout(10)
local line = client:receive("*l")
if line then client:send(line .. "\n") end
client:close()Pętla akceptowania
Klasyczny serwer iteracyjny działa w nieskończonej pętli: akceptuje klienta, obsługuje go, zamyka połączenie i powtarza ten cykl. Obsługuje w ten sposób jednego klienta naraz.
Jest prosty i poprawny, ale nie potrafi obsługiwać klientów współbieżnie, ponieważ powolne żądanie blokuje wszystkie kolejne.
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
endMinimalny serwer echo
Po połączeniu wszystkich elementów serwer echo przypisuje adres, zaczyna nasłuchiwać, a następnie w pętli odsyła pierwszą linię każdego klienta.
Jest to najmniejszy kompletny serwer LuaSocket i przydatny cel dla zbudowanego wcześniej klienta.
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()
endWspółbieżność z użyciem select
Aby obsługiwać wielu klientów jednocześnie bez używania wątków, należy użyć socket.select. Zwraca ono gniazda gotowe do odczytu, w tym nasłuchujące gniazdo serwera, gdy w kolejce oczekuje nowy klient.
Należy zarządzać tabelą aktywnych klientów i przetwarzać tylko te, dla których są dostępne dane, dzięki czemu jednowątkowa pętla zdarzeń pozostaje responsywna.
local readable = socket.select(watch, nil, 1)
for _, sock in ipairs(readable) do
if sock == server then
table.insert(watch, server:accept())
end
endNieblokujące akceptowanie
Należy ustawić server:settimeout(0), aby accept nigdy nie blokował działania. Trzeba połączyć to z select, wywołując accept tylko wtedy, gdy gniazdo nasłuchujące jest rzeczywiście gotowe do odczytu.
Stanowi to podstawę skalowalnego serwera działającego w jednym procesie, który multipleksuje setki połączeń.
server:settimeout(0)
local ready = socket.select({server}, nil, 5)
if #ready > 0 then
local c = server:accept()
endObsługa błędów klientów
Klienci mogą nagle się rozłączać. Gdy receive zwróci nil, "closed" lub częściowy bufor, należy usunąć tego klienta z tabeli monitorowania i zamknąć jego gniazdo.
Nigdy nie należy pozwolić, aby jedno uszkodzone połączenie zatrzymało pętlę akceptowania; błędy każdego klienta trzeba odizolować.
local data, err = client:receive("*l")
if err == "closed" then
client:close()
remove_from_watch(client)
endPoprawne zamykanie
Podczas zamykania należy przestać akceptować połączenia, zamknąć wszystkie aktywne gniazda klientów, a następnie zamknąć serwer nasłuchujący, aby zwolnić port.
Ustawienie reuseaddr podczas przypisywania adresu pozwala natychmiast ponownie uruchomić serwer bez oczekiwania na upływ okresu TCP TIME_WAIT.
for _, c in ipairs(clients) do c:close() end
server:close()
print("server stopped")Szybki sprawdzian
Wybierz sekwencję wywołań, która przekształca świeże gniazdo nadrzędne w działające gniazdo nasłuchujące.
Podsumowanie
Zbudowali Państwo serwer TCP: przypisali adres za pomocą reuseaddr, rozpoczęli nasłuchiwanie z określoną długością kolejki i uruchomili pętlę z accept do obsługi klientów.
Poznali Państwo prostą pętlę iteracyjną, a następnie skalowali ją za pomocą socket.select, uzyskując nieblokującą współbieżność, izolację błędów i poprawne zamykanie. Następnie przejdziemy do warstwy HTTP.
Często zadawane pytania
Czy lekcja „Budowanie serwera” jest bezpłatna?
Tak — pełny tekst „Budowanie serwera” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Budowanie serwera”?
Zaakceptuje Pan/Pani przychodzące połączenia. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Lua Academy?
Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Budowanie serwera”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?
Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Podstawy TCP
- Budowanie klienta
- Budowanie serwera
- Żądania HTTP