0Pricing
Lua Academy · Урок

Создание сервера

Принимайте входящие соединения.

«Создание сервера» — бесплатный урок Lua Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 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())

Привязка к порту

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. Он возвращает сокеты, готовые к чтению, включая серверный сокет прослушивания, когда ожидает новое подключение.

Вы управляете таблицей активных клиентов и обрабатываете только те сокеты, в которых есть данные, поддерживая отзывчивость однопоточного цикла обработки событий.

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" или частичный буфер, удалите этого клиента из таблицы отслеживаемых соединений и закройте его сокет.

Никогда не позволяйте одному неисправному соединению остановить цикл принятия подключений: изолируйте сбои каждого клиента.

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, запустили прослушивание с ограничением длины очереди и организовали цикл на accept для обслуживания клиентов.

Вы рассмотрели простой итеративный цикл, а затем масштабировали его с помощью socket.select для неблокирующей параллельной обработки, добавив изоляцию ошибок и корректное завершение работы. Далее Вы перейдёте на уровень HTTP.

Часто задаваемые вопросы

Урок «Создание сервера» бесплатный?

Да — полный текст урока «Создание сервера» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Создание сервера»?

Принимайте входящие соединения. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 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