# WebSocket `http/ws-*` 提供 RFC 6455 帧式双向流——客户端和服务器两端皆可—— 基于明文 `ws://`(客户端侧可通过 mbedTLS 使用 `wss://`)。该 API 与 `net/*` 对应,并使用相同的按 fd 的 epoll 回调。 ## `http/ws-*` 标准库函数 | 函数 | 返回值 | 用途 | |---|---|---| | `[http/ws-server $port %{ :on-connect $fn }]` | ws_server 资源 | 启动 WebSocket 服务器 | | `[http/ws-connect $url %{ :on-message $fn :on-close $fn :headers $map }]` | ws_conn 的 future | 连接到服务器 | | `[http/ws-send $conn $msg]` | nil | 发送文本帧 | | `[http/ws-send-binary $conn $bytes]` | nil | 发送二进制帧 | | `[http/ws-ping $conn]` | nil | 发送 ping 帧 | | `[http/ws-close $conn ?code ?reason]` | nil | 关闭连接 | | `[http/ws-on-message $conn $fn]` | nil | 注册 on-message 回调 | | `[http/ws-on-close $conn $fn]` | nil | 注册 on-close 回调 | | `[http/ws-stop $server]` | nil | 停止服务器 | ## WebSocket 服务器
def on-connect {|conn|
    @doc "A new client connected. Register handlers on the connection."
    echo "ws client connected"
    http/ws-on-message $conn { |msg|
        echo "received: $msg"
        http/ws-send $conn "echo: $msg"
    }
    http/ws-on-close $conn {
        echo "ws client disconnected"
    }
}

def srv [http/ws-server 8080 %{ :on-connect $on-connect }]
echo "ws server on :8080"
sleep 60000
## WebSocket 客户端 `http/ws-connect` 返回一个 future,握手完成后解析为 `ws_conn` 资源。在选项映射中传入回调即可从一开始就处理消息, 或者稍后用 `http/ws-on-message` 附加。
def on-message {|msg| echo "got: $msg" }
def on-close {|code reason| echo "closed: $code $reason" }

def conn-fut [http/ws-connect "ws://echo.example.com" %{
    :on-message $on-message
    :on-close $on-close
}]

def conn [await $conn-fut]
http/ws-send $conn "hello"

# For TLS:
# def conn-fut [http/ws-connect "wss://api.example.com" %{ :on-message $on-message }]
## 帧 三种帧类型:文本、二进制和 ping。用对应的标准库函数发送:
http/ws-send $conn "plain text frame"
http/ws-send-binary $conn $byte-list
http/ws-ping $conn                              # server should auto-pong
`on-message` 回调对每个文本或二进制帧触发一次。二进制帧以字节值 列表的形式到达;文本帧以字符串形式到达。 ## 关闭
http/ws-close $conn                              # default code, no reason
http/ws-close $conn 1000 "bye"                   # explicit code and reason
标准关闭码:`1000`(正常)、`1001`(离开)、`1008`(策略违规)、 `1011`(服务器错误)。远端的 `on-close` 处理器会收到 `(code, reason)`。 ## 服务器生命周期
def srv [http/ws-server 8080 %{ :on-connect $on-connect }]

# ... run for a while ...

http/ws-stop $srv                                # stop accepting, drop connections
## 架构说明 - 每个 `WsConn` 在 `std.heap.c_allocator` 上堆分配,因此在启动它 的 VM 结束后仍然存活(与 HTTP 服务器的设计一致)。 - 按 fd 的 epoll 回调驱动状态机:握手阶段 → 打开 → 帧解析器。 - 帧是增量解析的;一次 `posix.read` 可能产生多个帧,而一个帧可能 跨越多次读取。 - `wss://` 客户端连接通过与 `http_async.zig` 相同的 BIO 回调模型 复用 mbedTLS。当前不支持服务器端 TLS。 - 回调在 epoll 回调内部同步触发,与 `net/on-data` 类似。 ## 帧大小限制 | 限制 | 默认值 | |---|---| | 读取缓冲区 | 16 KB | | 最大帧大小 | 1 MB | | 最大握手大小 | 64 KB | 大于 1 MB 的帧会被拒绝,并关闭连接。 ## 示例 ### 广播服务器
def clients ^{}

def on-connect {|conn|
    @doc "Track clients in a set so we can broadcast to all."
    $clients << $conn
    http/ws-on-message $conn { |msg|
        # Broadcast to every connected client
        for c in $clients {
            if ($c != $conn) { http/ws-send $c $msg }
        }
    }
    http/ws-on-close $conn {
        # Manual removal — sets don't support removal, so re-add all-but-this
        set clients [into ^{} [filter [collect $clients] { $it != $conn }]]
    }
}

def srv [http/ws-server 8080 %{ :on-connect $on-connect }]
sleep 600000
### JSON RPC 客户端
def on-message {|msg|
    try {
        set data [json/parse $msg]
        echo "result: $data~result"
    } catch _e {
        echo "bad json: $msg"
    }
}

def c [await [http/ws-connect "wss://rpc.example.com" %{ :on-message $on-message }]]

http/ws-send $c [json/stringify %{ :jsonrpc "2.0" :id 1 :method "ping" }]
## 快速参考 | 形式 | 用途 | |---|---| | `[http/ws-server $port %{ :on-connect $fn }]` | 启动服务器 | | `[http/ws-connect $url %{ :on-message $fn ... }]` | 连接(返回 future) | | `[http/ws-send $conn $msg]` | 文本帧 | | `[http/ws-send-binary $conn $bytes]` | 二进制帧 | | `[http/ws-ping $conn]` | Ping | | `[http/ws-close $conn ?code ?reason]` | 关闭 | | `[http/ws-on-message $conn $fn]` | 设置消息处理器 | | `[http/ws-on-close $conn $fn]` | 设置关闭处理器 | | `[http/ws-stop $server]` | 停止服务器 |