# TCP 与 UDP `net/*` 提供事件驱动的 TCP/UDP 服务器和出站客户端连接。所有 I/O 都是非阻塞的,运行在 VM 的 epoll 事件循环上——数据到达时通过回调 触发处理器。 服务器和连接是 `native_resource` 值:由 GC 跟踪、在终结器中关闭、 可从 REPL 动态启动和停止。 ## `net/*` 标准库函数 | 函数 | 返回值 | 用途 | |---|---|---| | `[net/tcp $port $on-connect]` | 服务器资源 | 启动 TCP 服务器 | | `[net/udp $port $on-data]` | 服务器资源 | 启动 UDP 服务器 | | `[net/stop $server]` | `:ok` | 停止接受连接(保留资源) | | `[net/start $server]` | `:ok` | 重新启动已停止的服务器 | | `[net/close $server]` | `:ok` | 永久关闭并断开所有连接 | | `[net/list]` | 列表 | 所有已注册的服务器 | | `[net/info $server]` | 映射 | 服务器名称/端口/协议/状态/连接 | | `[net/connections $server]` | 列表 | 活动连接 | | `[net/connect $host $port]` | 连接资源 | 出站 TCP 客户端 | | `[net/connect-tls $host $port]` | 连接资源 | 出站 TLS 客户端(mbedTLS) | | `[net/send $conn $data]` | 已写入字节数或 `%Err` | 发送 | | `[net/recv $conn]` | 字符串或 nil | 读取可用数据 | | `[net/on-data $conn $fn]` | nil | 注册原始数据回调 | | `[net/on-line $conn $fn]` | nil | 注册按行模式回调 | | `[net/on-close $conn $fn]` | nil | 注册关闭回调 | | `[net/close-conn $conn]` | nil | 关闭一个连接 | | `[net/udp-send $server $addr $port $data]` | 字节数或 `%Err` | 发送 UDP 数据报 | ## TCP 服务器
def on-connect {|conn|
    @doc "Called with a fresh connection resource on each accept."
    echo "new connection from" $conn
    net/on-line $conn { |line|
        echo "received: $line"
        net/send $conn "echo: $line\n"
    }
}

def srv [net/tcp 8080 $on-connect]

# Server runs on the event loop. Stop or close to clean up:
# net/stop $srv      # stop accepting, keep resource
# net/close $srv     # permanent close, drops all connections
连接处理器会收到一个代表该连接的 `native_resource`。在其上注册 `on-line`、`on-data` 和 `on-close` 回调来驱动协议。 ## UDP 服务器
def on-data {|datagram|
    @doc "Called with each UDP datagram arrival."
    echo "got:" $datagram~data "from" $datagram~addr
}

def srv [net/udp 9090 $on-data]

# To send back: use net/udp-send with the server, addr, and port
# net/udp-send $srv "127.0.0.1" $client-port "reply\n"
UDP 是无连接的——没有按连接的资源,只有到达服务器的数据报。 ## 客户端连接
def conn [net/connect "example.com" 80]
net/send $conn "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"

set received ""
net/on-data $conn { |data|
    set received ($received + $data)
    if [ends-with? $received "</html>"] {
        echo "got full response"
        net/close-conn $conn
    }
}

# For TLS:
def tls-conn [net/connect-tls "api.github.com" 443]
## 回调 `net/on-data`、`net/on-line` 和 `net/on-close` 在连接上注册闭包。 再次调用即可替换。
net/on-data $conn { |data| echo "raw bytes: $data(len)" }
net/on-line $conn { |line| echo "line: $line" }
net/on-close $conn { echo "connection closed" }
`on-line` 按换行符拆分传入数据,每行触发一次。`on-data` 每次原始 读取触发一次。 ## 服务器生命周期
def srv [net/tcp 8080 $on-connect]

[net/info $srv]
# => %{ :name "tcp:8080" :port 8080 :protocol :tcp :state :running :connections @{} }

[net/connections $srv]
# => @{ %{ :addr "127.0.0.1" :port 54321 } ... }

net/stop $srv                                  # stop accepting, keeps connections
net/start $srv                                 # start accepting again
net/close $srv                                 # permanent: stop + drop connections + free resource
## 服务器内省
[net/list]
# => @{ %{ :name "tcp:8080" :port 8080 :protocol :tcp :state :running } ... }
## TLS 出站 TLS 使用 mbedTLS。连接通过与普通 TCP 相同的按 fd 的 epoll 回调驱动一个小型状态机(连接 → 握手 → 就绪);就绪后,`net/send` 和 `net/on-line` 会透明地使用 `mbedtls_ssl_write` 和 `mbedtls_ssl_read`。
def c [net/connect-tls "api.github.com" 443]
net/send $c "GET / HTTP/1.1\r\nHost: api.github.com\r\nConnection: close\r\n\r\n"
net/on-line $c { |line| echo $line }
当前不支持服务器端 TLS。如果需要终止 TLS,请使用反向代理 (nginx、caddy)。 ## 事件循环 `deft` 脚本二进制驱动单个事件循环。要处理传入连接和回调,脚本 必须持续运行——要么通过显式的 `vwait`(在协程上下文中),要么在 设置好服务器和回调后运行到脚本末尾。
def srv [net/tcp 8080 $on-connect]
echo "listening on :8080"
# script blocks here, event loop dispatches callbacks
sleep 60000                                    # crude: keep alive 60s
在 TUI 应用中,工作区的应用线程循环会自动驱动事件循环。 ## 示例 ### 回显服务器
def on-connect {|conn|
    net/on-line $conn { |line|
        net/send $conn "echo: $line\n"
    }
}

def srv [net/tcp 8080 $on-connect]
echo "echo server on :8080"
sleep 600000
### HTTP 请求
def c [net/connect "example.com" 80]
net/send $c "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"

set body ""
net/on-data $c { |data|
    set body ($body + $data)
}
net/on-close $c {
    echo "got $($body(len)) bytes"
}
## 快速参考 | 形式 | 用途 | |---|---| | `[net/tcp $port $on-connect]` | 启动 TCP 服务器 | | `[net/udp $port $on-data]` | 启动 UDP 服务器 | | `[net/connect $host $port]` | 出站 TCP | | `[net/connect-tls $host $port]` | 出站 TLS | | `[net/send $conn $data]` | 发送 | | `[net/on-line $conn $fn]` | 按行回调 | | `[net/on-data $conn $fn]` | 按读取回调 | | `[net/on-close $conn $fn]` | 关闭回调 | | `[net/stop $srv]` / `[net/start $srv]` | 暂停/恢复 | | `[net/close $srv]` | 永久关闭 | | `[net/list]` / `[net/info $srv]` | 内省 |