WebSocket Client
Модуль клиента WebSocket для подключения к удаленным WebSocket/WSS серверам. Поддерживает как незащищенные (ws://), так и защищенные (wss://) соединения.
Особенности
- Поддержка WebSocket (ws://) и WebSocket Secure (wss://)
- Автоматический handshake по RFC 6455
- Маскирование клиентских данных (соответствует стандарту)
- Автоматическое переподключение при разрыве соединения
- Активный PING/PONG мониторинг (отправка PING каждые 10 секунд)
- Обнаружение мертвых соединений (таймаут PONG 15 секунд)
- Автоматическая фрагментация больших сообщений (>2KB)
- Очередь входящих сообщений
- До 4 одновременных подключений
- Неблокирующее получение данных
websocket.connect(url [, auto_reconnect [, ca_cert]])
Подключается к удаленному WebSocket серверу.
Аргументы:
- url: URL сервера в формате ws://host:port/path или wss://host:port/path
- auto_reconnect: включить автоматическое переподключение. По умолчанию
false. - ca_cert: для
wss://— PEM-сертификат, PEM-bundle или путь к PEM-файлу в файловой системе устройства. Аргумент обязателен, если проверка сертификата включена. Размер источника — не более 64 КиБ.
Возвращает:
- handle (число) — непрозрачный дескриптор соединения при успехе. Передавайте его функциям модуля без изменений.
- nil, error (строка) - при ошибке
Модуль не содержит встроенного хранилища доверенных CA. Для WSS передайте собственный актуальный корневой сертификат или bundle. В отладочных сценариях проверку можно отключить через net.skip_ssl_verify(true), но это делает соединение уязвимым для атаки посредника.
Дескриптор содержит поколение внутреннего слота. После websocket.close() он становится недействительным: даже если слот займёт новое соединение, старый дескриптор не сможет отправить, получить или закрыть его данные.
Для сборки модуль должен быть включён параметром CONFIG_LUA_RTOS_LUA_USE_WEBSOCKET. Поддержка WSS управляется отдельным параметром CONFIG_LUA_RTOS_WEBSOCKET_SSL.
local websocket = require("websocket")
-- Подключение без автопереподключения
local handle, err = websocket.connect("ws://echo.websocket.org")
if not handle then
print("Connection failed: " .. err)
return
end
print("Connected! Handle: " .. handle)
-- Подключение с автоматическим переподключением
local handle = websocket.connect(
"wss://api.example.com:443/socket",
true,
"/certs/root-ca.pem"
)
if handle then
print("Connected with auto-reconnect enabled")
end
websocket.send(handle, data)
Отправляет текстовое сообщение на сервер.
Аргументы:
- handle: дескриптор, возвращенный
websocket.connect(). - data: текстовые данные для отправки (строка)
Возвращает:
- true при успехе
- false, error (строка) - при ошибке
local websocket = require("websocket")
local handle = websocket.connect("ws://echo.websocket.org")
-- Отправка сообщения
local ok, err = websocket.send(handle, "Hello WebSocket!")
if not ok then
print("Send failed: " .. err)
end
-- Отправка JSON данных
local cjson = require("cjson")
local data = {temperature = 25.5, humidity = 60}
websocket.send(handle, cjson.encode(data))
websocket.recv(handle [, timeout_ms])
Получает сообщение с сервера (неблокирующий или с таймаутом).
Аргументы:
- handle: дескриптор соединения.
- timeout_ms: необязательный таймаут в миллисекундах (по умолчанию 0 - неблокирующий)
Возвращает:
- message (строка) - полученное сообщение
- nil - если сообщений нет
local websocket = require("websocket")
local handle = websocket.connect("ws://echo.websocket.org")
-- Неблокирующее получение
local msg = websocket.recv(handle)
if msg then
print("Received: " .. msg)
else
print("No messages")
end
-- Блокирующее получение с таймаутом 5 секунд
local msg = websocket.recv(handle, 5000)
if msg then
print("Received: " .. msg)
else
print("Timeout or no messages")
end
websocket.is_connected(handle)
Проверяет, активно ли соединение.
Аргументы:
- handle: дескриптор соединения.
Возвращает: true если подключен, false иначе
local websocket = require("websocket")
local handle = websocket.connect("ws://echo.websocket.org")
if websocket.is_connected(handle) then
print("Still connected")
websocket.send(handle, "ping")
else
print("Disconnected")
end
websocket.close(handle)
Закрывает WebSocket соединение.
Аргументы:
- handle: дескриптор соединения.
Возвращает: ничего
local websocket = require("websocket")
local handle = websocket.connect("ws://echo.websocket.org")
-- ... работа с соединением ...
websocket.close(handle)
print("Connection closed")
Полный пример: Echo клиент
local websocket = require("websocket")
-- Подключение
local handle, err = websocket.connect("ws://echo.websocket.org")
if not handle then
print("Error: " .. err)
return
end
print("Connected to echo server")
-- Отправка сообщения
websocket.send(handle, "Hello, WebSocket!")
-- Ожидание ответа (5 секунд)
local msg = websocket.recv(handle, 5000)
if msg then
print("Echo response: " .. msg)
else
print("No response received")
end
-- Закрытие
websocket.close(handle)
Пример: Отправка данных датчиков с автопереподключением
local websocket = require("websocket")
local cjson = require("cjson")
-- Подключение к серверу мониторинга с автопереподключением
local handle = websocket.connect(
"wss://monitoring.example.com/sensors",
true,
"/certs/root-ca.pem"
)
if not handle then
print("Connection failed")
return
end
-- Отправка данных каждые 10 секунд
-- При разрыве соединения автоматически переподключится
while true do
-- Проверяем статус подключения
if websocket.is_connected(handle) then
local data = {
device_id = "esp32-001",
temperature = 25.5,
humidity = 60,
timestamp = os.time()
}
local json = cjson.encode(data)
local ok = websocket.send(handle, json)
if not ok then
print("Send failed, waiting for auto-reconnect...")
end
-- Проверка команд с сервера
local msg = websocket.recv(handle, 100)
if msg then
print("Server command: " .. msg)
local cmd = cjson.decode(msg)
if cmd.action == "reboot" then
os.reboot()
end
end
else
print("Disconnected, auto-reconnect in progress...")
end
tmr.delayms(10000)
end
websocket.close(handle)
Пример: Двусторонняя связь
local websocket = require("websocket")
local thread = require("thread")
local handle, err = websocket.connect(
"wss://chat.example.com/room",
false,
"/certs/root-ca.pem"
)
if not handle then
error(err)
end
-- Поток приема сообщений
thread.start(function()
while websocket.is_connected(handle) do
local msg = websocket.recv(handle, 1000)
if msg then
print("Received: " .. msg)
end
end
end)
-- Основной поток отправки
while websocket.is_connected(handle) do
local input = io.read()
if input == "quit" then
break
end
websocket.send(handle, input)
end
websocket.close(handle)
Надежность соединения
Модуль включает несколько механизмов для обеспечения надежности:
Активный PING/PONG мониторинг
- Автоматически отправляет PING каждые 10 секунд
- Ожидает PONG в течение 15 секунд
- При отсутствии PONG отключается (триггер для автопереподключения)
- Помогает обнаруживать мертвые соединения через NAT/прокси
Автоматическое переподключение
При включении автопереподключения (websocket.connect(url, true)):
- При обрыве соединения автоматически пытается переподключиться
- Задержка между попытками: 5 секунд
- Продолжает попытки до явного вызова websocket.close()
- Все отправленные сообщения во время разрыва будут потеряны
-- Включение автопереподключения
local handle = websocket.connect(
"wss://server.com/socket",
true,
"/certs/root-ca.pem"
)
-- Соединение будет автоматически восстанавливаться при разрыве
while true do
if websocket.is_connected(handle) then
websocket.send(handle, "heartbeat")
else
-- Переподключение происходит автоматически
print("Waiting for reconnection...")
end
tmr.delayms(5000)
end
Фрагментация больших сообщений
- Сообщения >2048 байт автоматически разбиваются на фреймы
- Соответствует RFC 6455 (continuation frames)
-- Отправка большого JSON (например, 10KB)
local large_data = cjson.encode(big_table)
websocket.send(handle, large_data) -- Автоматически фрагментируется
Ограничения и параметры
- Максимум 4 одновременных подключения
- Максимальный размер входящего сообщения: 2048 байт
- Размер очереди сообщений: 10 сообщений на клиента
- Входящие TEXT- и BINARY-фреймы возвращаются как строки Lua. Тип фрейма отдельно не возвращается.
- Исходящие сообщения автоматически фрагментируются по 2048 байт
- Интервал отправки PING: 10 секунд
- Таймаут ожидания PONG: 15 секунд
- Задержка переподключения: 5 секунд
Обработка ошибок
local websocket = require("websocket")
local handle, err = websocket.connect("ws://invalid-server.com")
if not handle then
print("Connection error: " .. err)
-- Возможные ошибки:
-- "Invalid URL scheme"
-- "Invalid port number"
-- "DNS lookup failed"
-- "Socket creation failed"
-- "Connection failed"
-- "CA certificate is required for WSS"
-- "CA certificate load failed"
-- "TLS handshake failed"
-- "WebSocket handshake read failed"
-- "No free client slots"
return
end
local ok, err = websocket.send(handle, "test")
if not ok then
print("Send error: " .. err)
-- Возможные ошибки:
-- "Invalid WebSocket handle"
-- "Client not connected"
-- "Send failed"
end