WebSocket-Client
WebSocket-Client für bidirektionale Echtzeit-Kommunikation mit Servern.
Laden
local websocket = require("websocket")
Verbinden
Einfache Verbindung
local client, err = websocket.connect("wss://api.example.com/ws")
if err then
return nil, err
end
Mit Optionen
local client, err = websocket.connect("wss://api.example.com/ws", {
headers = {
["Authorization"] = "Bearer " .. token
},
protocols = {"graphql-ws"},
dial_timeout = "10s",
read_timeout = "30s",
compression = websocket.COMPRESSION.CONTEXT_TAKEOVER
})
| Parameter | Typ | Beschreibung |
|---|---|---|
url |
string | WebSocket-URL (ws:// oder wss://) |
options |
table | Verbindungsoptionen (optional) |
Gibt zurück: Client, error
Verbindungsoptionen
| Option | Typ | Beschreibung |
|---|---|---|
headers |
table | HTTP-Header für Handshake |
protocols |
table | WebSocket-Subprotokolle |
dial_timeout |
number/string | Verbindungs-Timeout (ms oder "5s") |
read_timeout |
number/string | Lese-Timeout |
write_timeout |
number/string | Schreib-Timeout |
compression |
number | Komprimierungsmodus (siehe Konstanten) |
compression_threshold |
number | Min. Größe zum Komprimieren (0-100MB) |
read_limit |
number | Max. Nachrichtengröße (0-128MB) |
channel_capacity |
number | Empfangs-Channel-Puffer (1-10000) |
Timeout-Format: Zahlen sind Millisekunden, Strings verwenden Go-Dauerformat ("5s", "1m").
Nachrichten senden
Textnachrichten
local ok, err = client:send("Hello, Server!")
if err then
return nil, err
end
-- JSON senden
client:send(json.encode({
type = "subscribe",
channel = "orders"
}))
Binarnachrichten
client:send(binary_data, websocket.BINARY)
| Parameter | Typ | Beschreibung |
|---|---|---|
data |
string | Nachrichteninhalt |
type |
number | websocket.TEXT (1) oder websocket.BINARY (2) |
Gibt zurück: boolean, error
Ping
client:ping()
Gibt zurück: boolean, error
Nachrichten empfangen
Die channel()-Methode gibt einen Channel zum Empfangen von Nachrichten zurück. Funktioniert mit channel.select für Multiplexing.
Einfaches Empfangen
local ch = client:channel()
local msg, ok = ch:receive()
if ok then
print("Type:", msg.type) -- "text" oder "binary"
print("Data:", msg.data)
end
Nachrichtenschleife
local ch = client:channel()
while true do
local msg, ok = ch:receive()
if not ok then
break -- Verbindung geschlossen
end
if msg.type == "text" then
local data = json.decode(msg.data)
handle_message(data)
end
end
Mit Select
local ch = client:channel()
local timeout = time.after("30s")
while true do
local r = channel.select {
ch:case_receive(),
timeout:case_receive()
}
if r.channel == timeout then
client:ping() -- Keep-Alive
timeout = time.after("30s")
else
local data = json.decode(r.value.data)
process(data)
end
end
Nachrichtenobjekt
| Feld | Typ | Beschreibung |
|---|---|---|
type |
string | "text" oder "binary" |
data |
string | Nachrichteninhalt |
Verbindung schließen
-- Normales Schließen (Code 1000)
client:close()
-- Mit Code und Grund
client:close(websocket.CLOSE_CODES.NORMAL, "Session ended")
-- Fehler-Schließen
client:close(websocket.CLOSE_CODES.INTERNAL_ERROR, "Processing failed")
| Parameter | Typ | Beschreibung |
|---|---|---|
code |
number | Schließ-Code (1000-4999), Standard 1000 |
reason |
string | Schließgrund (optional) |
Gibt zurück: boolean, error
Konstanten
Nachrichtentypen
-- Numerisch (für send)
websocket.TEXT -- 1
websocket.BINARY -- 2
-- String (empfangener Nachrichtentyp-Feld)
websocket.TYPE_TEXT -- "text"
websocket.TYPE_BINARY -- "binary"
websocket.TYPE_PING -- "ping"
websocket.TYPE_PONG -- "pong"
websocket.TYPE_CLOSE -- "close"
Komprimierungsmodi
websocket.COMPRESSION.DISABLED -- 0 (keine Komprimierung)
websocket.COMPRESSION.CONTEXT_TAKEOVER -- 1 (gleitendes Fenster)
websocket.COMPRESSION.NO_CONTEXT -- 2 (pro Nachricht)
Schließ-Codes
| Konstante | Code | Beschreibung |
|---|---|---|
NORMAL |
1000 | Normales Schließen |
GOING_AWAY |
1001 | Server fährt herunter |
PROTOCOL_ERROR |
1002 | Protokollfehler |
UNSUPPORTED_DATA |
1003 | Nicht unterstützter Datentyp |
NO_STATUS |
1005 | Kein Status empfangen |
ABNORMAL_CLOSURE |
1006 | Verbindung verloren |
INVALID_PAYLOAD |
1007 | Ungültiger Frame-Payload |
POLICY_VIOLATION |
1008 | Richtlinienverletzung |
MESSAGE_TOO_BIG |
1009 | Nachricht zu groß |
INTERNAL_ERROR |
1011 | Serverfehler |
SERVICE_RESTART |
1012 | Server startet neu |
TRY_AGAIN_LATER |
1013 | Server überlastet |
client:close(websocket.CLOSE_CODES.NORMAL, "Done")
Beispiele
Echtzeit-Chat
local function connect_chat(room_id, on_message)
local client, err = websocket.connect("wss://chat.example.com/ws", {
headers = {["Authorization"] = "Bearer " .. token}
})
if err then
return nil, err
end
-- Raum beitreten
client:send(json.encode({
type = "join",
room = room_id
}))
-- Nachrichtenschleife
local ch = client:channel()
while true do
local msg, ok = ch:receive()
if not ok then break end
local data = json.decode(msg.data)
on_message(data)
end
client:close()
end
Preis-Stream mit Keep-Alive
local client = websocket.connect("wss://stream.example.com/prices")
client:send(json.encode({
action = "subscribe",
symbols = {"BTC-USD", "ETH-USD"}
}))
local ch = client:channel()
local heartbeat = time.after("30s")
while true do
local r = channel.select {
ch:case_receive(),
heartbeat:case_receive()
}
if r.channel == heartbeat then
client:ping()
heartbeat = time.after("30s")
elseif not r.ok then
break -- Verbindung geschlossen
else
local price = json.decode(r.value.data)
update_price(price.symbol, price.value)
end
end
client:close()
Berechtigungen
WebSocket-Verbindungen unterliegen der Sicherheitsrichtlinienauswertung.
Sicherheitsaktionen
| Aktion | Ressource | Beschreibung |
|---|---|---|
websocket.connect |
- | WebSocket-Verbindungen erlauben/verweigern |
websocket.connect.url |
URL | Verbindungen zu bestimmten URLs erlauben/verweigern |
Siehe Sicherheitsmodell für Richtlinienkonfiguration.
Fehler
| Bedingung | Art | Wiederholbar |
|---|---|---|
| Verbindungen deaktiviert | errors.PERMISSION_DENIED |
nein |
| URL nicht erlaubt | errors.PERMISSION_DENIED |
nein |
| Kein Kontext | errors.INTERNAL |
nein |
| Verbindung fehlgeschlagen | errors.INTERNAL |
ja |
| Ungültige Verbindungs-ID | errors.INTERNAL |
nein |
local client, err = websocket.connect(url)
if err then
if errors.is(err, errors.PERMISSION_DENIED) then
print("Access denied:", err:message())
elseif err:retryable() then
print("Temporary error:", err:message())
end
return nil, err
end
Siehe Fehlerbehandlung für die Arbeit mit Fehlern.