Budowanie klienta
Poprosi Pan/Pani serwer o dane.
Budowanie klienta to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 2 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 klienta
Klient TCP przechodzi przez jasno określony cykl życia: tworzy gniazdo, łączy się z serwerem, wymienia dane, a następnie je zamyka.
W LuaSocket każdy etap jest pojedynczym wywołaniem metody i każde takie wywołanie może się nie powieść. Dobrze napisany klient sprawdza każdą zwracaną wartość i zamyka swoje gniazdo na każdej ścieżce błędu.
local socket = require("socket")
local client = assert(socket.tcp())Bezpieczne nawiązywanie połączenia
Przed wywołaniem connect należy ustawić limit czasu połączenia, aby niedostępny host nie zawiesił programu. Typowa wartość to kilka sekund.
Jeśli connect zwróci nil, należy zarejestrować błąd i przerwać działanie. Nigdy nie należy zakładać, że uzgadnianie połączenia zakończyło się powodzeniem.
client:settimeout(5)
local ok, err = client:connect("127.0.0.1", 8080)
if not ok then
client:close()
error("connect failed: " .. err)
endUżywanie socket.connect
W typowym przypadku socket.connect(host, port) łączy utworzenie gniazda z nawiązaniem połączenia. Zwraca gotowy obiekt klienta albo nil i błąd.
Ta forma jest zwięzła, ale nie pozwala ustawić limitu czasu przed uzgadnianiem połączenia, dlatego w zawodnych sieciach należy preferować formę jawną.
local socket = require("socket")
local client, err = socket.connect("example.com", 13)
if not client then error(err) endWysyłanie żądania
Po nawiązaniu połączenia należy wysłać bajty żądania za pomocą send. Wiele protokołów tekstowych rozdziela wiersze sekwencją powrotu karetki i nowego wiersza (\r\n).
Ponieważ TCP jest strumieniem, każdy logiczny komunikat należy wyraźnie zakończyć, aby serwer wiedział, gdzie się on kończy.
local msg = "PING\r\n"
local sent, err = client:send(msg)
if not sent then error("send failed: " .. err) endOdczytywanie odpowiedzi wiersz po wierszu
W przypadku protokołów opartych na wierszach należy odczytywać dane w pętli za pomocą wzorca "*l". Każde wywołanie zwraca jeden wiersz bez terminatora.
W przypadku nil należy sprawdzić błąd: "closed" oznacza, że serwer zamknął połączenie, natomiast "timeout" oznacza, że dane nie nadeszły w odpowiednim czasie.
client:settimeout(5)
local line, err = client:receive("*l")
if line then
print("server said:", line)
else
print("recv error:", err)
endOdczytywanie całej odpowiedzi
Protokoły żądanie–odpowiedź często odczytują wszystkie dane aż do zamknięcia połączenia przez serwer. Należy użyć "*a", aby przechwycić całą treść.
Jeśli najpierw zostanie połowicznie zamknięta strona wysyłająca za pomocą shutdown("send"), serwer zobaczy koniec danych wejściowych i będzie mógł dokończyć odpowiedź.
client:send("GET DATA\r\n")
client:shutdown("send")
local body, err = client:receive("*a")
print(#(body or ""), "bytes received")Ramkowanie o stałej długości
Protokoły binarne często poprzedzają każdą wiadomość jej długością. Najpierw należy odczytać nagłówek długości, a następnie dokładnie taką liczbę bajtów.
Przekazanie liczby do receive blokuje działanie do chwili odebrania tej liczby bajtów lub wystąpienia błędu gniazda, zapewniając precyzyjne ramkowanie w strumieniu bajtów.
local header = client:receive(4)
local len = string.unpack(">I4", header)
local payload = client:receive(len)Kompletny klient echo
Oto cały przebieg: nawiązanie połączenia, wysłanie wiersza, odczytanie odesłanego wiersza i zamknięcie połączenia. Jest to typowy schemat klienta LuaSocket.
Każde wywołanie, które może się nie powieść, jest dla zwięzłości zabezpieczone za pomocą assert, ale rzeczywisty klient powinien obsługiwać błędy w kontrolowany sposób.
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()Obsługa rozłączeń
Serwery mogą w dowolnym momencie przerwać połączenie. Wywołanie send dla zamkniętej drugiej strony może zwrócić nil, "closed", a receive zwraca częściowe dane wraz z błędem.
Wartość "closed" należy traktować jako normalny stan końcowy, a nie awarię. Logika ponownego łączenia powinna znajdować się w opakowaniu ponawiającym próby wokół klienta.
local data, err, partial = client:receive("*a")
if err == "closed" then
print("peer closed, got", #partial, "bytes")
endKlienci nieblokujący
Aby uzyskać w pełni nieblokującego klienta, należy ustawić limit czasu na 0. Wywołania będą wtedy natychmiast zwracać wynik, sygnalizując "timeout", gdy nie można wykonać żadnego postępu.
Należy połączyć to z socket.select, aby efektywnie oczekiwać na gotowość wielu gniazd bez aktywnego oczekiwania.
client:settimeout(0)
local r = socket.select({client}, nil, 5)
if #r > 0 then print(client:receive("*l")) endRozwiązywanie nazw hostów
Jeśli połączenie jest nawiązywane za pomocą nazwy hosta, LuaSocket rozwiązuje ją automatycznie. Aby sprawdzić lub buforować wynik tego rozwiązywania, należy samodzielnie wywołać socket.dns.toip lub socket.dns.getaddrinfo.
Jednorazowe rozwiązanie nazwy i łączenie się przez adres IP pozwala uniknąć wielokrotnych zapytań DNS w pętli częstego ponawiania połączenia.
local socket = require("socket")
local ip = assert(socket.dns.toip("example.com"))
local c = assert(socket.connect(ip, 80))Szybki sprawdzian
Wybierz właściwy sposób odczytania wszystkich danych wysyłanych przez serwer aż do chwili jego zamknięcia.
Podsumowanie
Zbudowali Państwo klienta TCP od początku do końca: nawiązali połączenie z limitem czasu, sformatowali i wysłali żądania, odczytali odpowiedzi wierszami, według liczby bajtów lub z całego strumienia, a następnie poprawnie zamknęli połączenie.
Poznali Państwo także obsługę rozłączeń, tryb nieblokujący z użyciem select oraz buforowanie wyników DNS. Następnie zostanie napisana część serwerowa odpowiadająca tym klientom.
Często zadawane pytania
Czy lekcja „Budowanie klienta” jest bezpłatna?
Tak — pełny tekst „Budowanie klienta” 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 klienta”?
Poprosi Pan/Pani serwer o dane. Ć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 2 z 4.
Ile czasu zajmuje lekcja „Budowanie klienta”?
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