0Pricing
Lua Academy · Lekcja

Podstawy TCP

Nawiąże Pan/Pani połączenie i wyśle dane.

Podstawy TCP to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 1 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.

Czym jest LuaSocket

LuaSocket to de facto standardowa biblioteka sieciowa dla Lua. Udostępnia niskopoziomowe gniazda TCP i UDP oraz pomocnicze funkcje wyższego poziomu do obsługi HTTP, SMTP i FTP.

Jest zewnętrznym modułem napisanym w C, więc nie należy do standardowej wersji Lua. Należy zainstalować go za pomocą LuaRocks i wczytać przy użyciu require.

Żaden z fragmentów tego kursu nie działa w zwykłym środowisku do uruchamiania kodu, ponieważ korzystają one z sieci.

local socket = require("socket")
print(socket._VERSION)

Tworzenie gniazda TCP

Podstawowym obiektem jest nadrzędne gniazdo TCP, tworzone za pomocą socket.tcp(). Nowo utworzone gniazdo nadrzędne nie jest jeszcze połączone ani przypisane do adresu.

Z poziomu gniazda nadrzędnego można wywołać connect (zmieniając je w obiekt klienta) albo bind+listen (zmieniając je w obiekt serwera).

Większość wywołań zwraca wartość albo nil wraz z ciągiem opisującym błąd, dlatego zawsze należy przechwytywać oba wyniki.

local socket = require("socket")
local tcp, err = socket.tcp()
if not tcp then error(err) end

Rodzina adresów

TCP działa przez IPv4 lub IPv6. socket.tcp() wybiera rodzinę adresów dopiero w razie potrzeby, natomiast socket.tcp4() i socket.tcp6() wymuszają użycie konkretnej rodziny.

Jeśli potrzebna jest jawna kontrola, przed połączeniem można użyć socket.dns.toip(host), aby rozwiązać nazwę hosta do adresu numerycznego.

local socket = require("socket")
local ip, info = socket.dns.toip("example.com")
print(ip)

Łączenie z hostem

conn:connect(host, port) wykonuje trójstronne uzgadnianie TCP. W przypadku powodzenia zwraca 1, a w przypadku niepowodzenia zwraca nil i komunikat błędu, taki jak "connection refused" lub "timeout".

Funkcja pomocnicza socket.connect(host, port) tworzy gniazdo i łączy je w jednym wywołaniu.

local socket = require("socket")
local conn, err = socket.connect("example.com", 80)
if not conn then print("failed:", err) end

Wysyłanie danych

conn:send(data) zapisuje bajty w gnieździe. Zwraca indeks ostatniego wysłanego bajtu. W przypadku gniazda blokującego jest to zazwyczaj pełna długość data.

TCP jest strumieniem bajtów, a nie protokołem komunikatów, dlatego pojedyncze wywołanie send może zostać podzielone lub połączone z innymi podczas przesyłania. Sposób ramkowania komunikatów należy zdefiniować samodzielnie.

local request = "GET / HTTP/1.0\r\n\r\n"
local sent, err = conn:send(request)
print("bytes sent:", sent)

Odbieranie danych

conn:receive(pattern) odczytuje dane ze strumienia. Domyślny wzorzec "*l" odczytuje jeden wiersz bez znaku nowej linii. Wzorzec "*a" odczytuje dane aż do zamknięcia połączenia.

Można również przekazać liczbę, aby odczytać dokładnie taką liczbę bajtów. W przypadku błędu funkcja zwraca nil, ciąg opisujący błąd oraz wszelkie częściowo odebrane dane.

local line, err = conn:receive("*l")
local chunk = conn:receive(512)
local all = conn:receive("*a")

Zamykanie połączenia

Po zakończeniu pracy zawsze należy wywołać conn:close(), aby zwolnić deskryptor pliku i wysłać segment TCP FIN.

Można częściowo zamknąć połączenie za pomocą conn:shutdown("send"), sygnalizując koniec strumienia i nadal odczytując odpowiedź drugiej strony. Jest to przydatne w protokołach żądanie–odpowiedź korzystających z "*a".

conn:shutdown("send")
local reply = conn:receive("*a")
conn:close()

Znaczenie limitów czasu

Domyślnie operacje na gniazdach blokują się bezterminowo. conn:settimeout(seconds) ogranicza czas oczekiwania wywołania. Wartość 0 sprawia, że gniazdo działa w trybie nieblokującym.

Po przekroczeniu limitu czasu wywołanie zwraca nil oraz ciąg "timeout". W środowisku produkcyjnym zawsze należy ustawiać limit czasu, aby uniknąć zawieszonych połączeń.

conn:settimeout(5)
local data, err = conn:receive("*l")
if err == "timeout" then print("too slow") end

TCP a UDP

TCP działa w oparciu o połączenie, zachowuje kolejność i jest niezawodny: bajty docierają dokładnie raz i we właściwej kolejności, kosztem uzgadniania połączenia oraz ponownych transmisji.

UDP (socket.udp()) nie wymaga połączenia i jest niezawodny, ale lekki, dlatego dobrze sprawdza się w telemetrii lub grach. Ten kurs koncentruje się na TCP, ponieważ stanowi ono podstawę HTTP.

Częściowe wysyłanie i pętle

W przypadku nieblokujących gniazd send może przesłać tylko część bufora. Zwraca ono nil, "timeout" oraz indeks ostatniego dotychczas zapisanego bajtu.

Solidny mechanizm wysyłający działa w pętli: wznawia wysyłanie od bajtu następującego po ostatnio wysłanym, aż cały bufor zostanie przesłany.

local i = 1
while i <= #data do
  local sent, err, last = conn:send(data, i)
  i = (sent or last) + 1
  if err and err ~= "timeout" then break end
end

Sprawdzanie połączenia

conn:getpeername() zwraca zdalny adres IP i port, natomiast conn:getsockname() zwraca lokalny adres i port. Informacje te pomagają w rejestrowaniu zdarzeń i debugowaniu.

conn:setoption("keepalive", true) oraz conn:setoption("tcp-nodelay", true) dostosowują zachowanie bazowego gniazda.

local ip, port = conn:getpeername()
print("connected to", ip, port)
conn:setoption("tcp-nodelay", true)

Szybki sprawdzian

Sprawdź swoją znajomość semantyki odbierania danych przez TCP.

Podsumowanie

Poznali Państwo główny obiekt TCP w LuaSocket, nauczyli się tworzyć, łączyć, używać do wysyłania i odbierania danych oraz zamykać gniazda, a także zobaczyli, jak limity czasu i połowiczne zamknięcie wpływają na działanie.

Należy pamiętać, że TCP jest strumieniem bajtów, każde wywołanie może zwrócić nil, err, a gniazdo produkcyjne zawsze powinno mieć ustawiony limit czasu. Następnie elementy te zostaną połączone w działającego klienta.

Często zadawane pytania

Czy lekcja „Podstawy TCP” jest bezpłatna?

Tak — pełny tekst „Podstawy TCP” 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 „Podstawy TCP”?

Nawiąże Pan/Pani połączenie i wyśle 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 1 z 4.

Ile czasu zajmuje lekcja „Podstawy TCP”?

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

  1. Podstawy TCP
  2. Budowanie klienta
  3. Budowanie serwera
  4. Żądania HTTP
← Powrót do Lua Academy