Compare commits

...
4 Commits
Author SHA1 Message Date
meiseayoung 0969901481 chore: update v.mod version 2026-01-05 11:50:46 +08:00
meiseayoung 6bddfc3731 build(usockets): add pre-compiled library for Linux platform 2026-01-05 11:49:47 +08:00
meiseayoung 26ac804b1d chore: update v.mod version 2026-01-05 11:07:41 +08:00
meiseayoung 56299b5485 refactor(usockets): reorganize lib directory structure for multi-platform support
- Organize lib directory by platform: windows/, macos-arm64/, macos-x64/, linux/
- Update build.sh to support unified build process for Windows/macOS/Linux
- Compile libuv + uSockets and merge into complete static library
- Update usockets.v conditional compilation to point to new directory structure
- Optimize benchmark tests with connection pooling for high concurrency testing
- Clean up unused legacy library files

Performance test results (Windows):
- 1000 concurrent, 1M requests: 35,223 req/s
- 10000 concurrent, 1M requests: 26,884 req/s
2026-01-05 11:06:56 +08:00
13 changed files with 151 additions and 63 deletions
+40 -12
View File
@@ -448,21 +448,49 @@ func checkKeepAlive(client *http.Client) bool {
func checkThroughput(client *http.Client) float64 { func checkThroughput(client *http.Client) float64 {
start := time.Now() start := time.Now()
success := 0 concurrency := 1000
requests := 200 totalRequests := 1000000
requestsPerWorker := totalRequests / concurrency
for i := 0; i < requests; i++ { // 创建共享的 Transport,启用连接池复用
resp, err := client.Get(baseURL + "/health") transport := &http.Transport{
if err != nil { MaxIdleConns: concurrency,
continue MaxIdleConnsPerHost: concurrency,
} IdleConnTimeout: 30 * time.Second,
io.Copy(io.Discard, resp.Body) DisableKeepAlives: false,
resp.Body.Close() }
if resp.StatusCode == 200 {
success++ results := make(chan int, concurrency)
}
for i := 0; i < concurrency; i++ {
go func() {
localSuccess := 0
// 每个 goroutine 使用独立 Client,但共享 Transport(连接池)
localClient := &http.Client{
Timeout: 10 * time.Second,
Transport: transport,
}
for j := 0; j < requestsPerWorker; j++ {
resp, err := localClient.Get(baseURL + "/health")
if err != nil {
continue
}
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
if resp.StatusCode == 200 {
localSuccess++
}
}
results <- localSuccess
}()
}
success := 0
for i := 0; i < concurrency; i++ {
success += <-results
} }
elapsed := time.Since(start).Seconds() elapsed := time.Since(start).Seconds()
fmt.Printf("\n [并发: %d, 总请求: %d, 成功: %d, 耗时: %.2fs]\n ", concurrency, totalRequests, success, elapsed)
return float64(success) / elapsed return float64(success) / elapsed
} }
+93 -26
View File
@@ -1,13 +1,36 @@
#!/bin/bash #!/bin/bash
# uSockets 编译脚本 # uSockets 编译脚本
# 用于重新编译 libusockets_full.a # 用于重新编译 libusockets_full.a (包含 uSockets + libuv)
# 支持: Windows (Git Bash/MSYS2), macOS (Intel/Apple Silicon), Linux
# 输出到: usockets/lib/{platform}/libusockets_full.a
set -e set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
USOCKETS_DIR="/tmp/uSockets" USOCKETS_DIR="/tmp/uSockets"
LIBUV_DIR="/tmp/libuv"
MERGE_DIR="/tmp/merge_libs"
echo "=== uSockets 编译脚本 ===" echo "=== uSockets 编译脚本 ==="
echo "检测到系统: $OSTYPE"
# 确定输出目录
if [[ "$OSTYPE" == "darwin"* ]]; then
if [[ $(uname -m) == "arm64" ]]; then
OUTPUT_DIR="$SCRIPT_DIR/lib/macos-arm64"
else
OUTPUT_DIR="$SCRIPT_DIR/lib/macos-x64"
fi
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "mingw"* ]]; then
OUTPUT_DIR="$SCRIPT_DIR/lib/windows"
elif [[ "$OSTYPE" == "linux"* ]]; then
OUTPUT_DIR="$SCRIPT_DIR/lib/linux"
else
OUTPUT_DIR="$SCRIPT_DIR/lib/linux"
fi
echo "输出目录: $OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
# 检查是否有 uSockets 源码 # 检查是否有 uSockets 源码
if [ ! -d "$USOCKETS_DIR" ]; then if [ ! -d "$USOCKETS_DIR" ]; then
@@ -15,41 +38,85 @@ if [ ! -d "$USOCKETS_DIR" ]; then
git clone --depth 1 https://github.com/uNetworking/uSockets.git "$USOCKETS_DIR" git clone --depth 1 https://github.com/uNetworking/uSockets.git "$USOCKETS_DIR"
fi fi
# 检查是否有 libuv 源码
if [ ! -d "$LIBUV_DIR" ]; then
echo "克隆 libuv..."
git clone --depth 1 --branch v1.48.0 https://github.com/libuv/libuv.git "$LIBUV_DIR"
fi
# 应用 backlog 修改 # 应用 backlog 修改
echo "应用 backlog=16384 修改..." echo "应用 backlog=16384 修改..."
if [ -f "$SCRIPT_DIR/src/bsd.c" ]; then if [ -f "$SCRIPT_DIR/src/bsd.c" ]; then
cp "$SCRIPT_DIR/src/bsd.c" "$USOCKETS_DIR/src/bsd.c" cp "$SCRIPT_DIR/src/bsd.c" "$USOCKETS_DIR/src/bsd.c"
else else
# 如果没有本地修改的源码,直接修改
sed -i.bak 's/listen(listenFd, 512)/listen(listenFd, 16384)/g' "$USOCKETS_DIR/src/bsd.c" sed -i.bak 's/listen(listenFd, 512)/listen(listenFd, 16384)/g' "$USOCKETS_DIR/src/bsd.c"
fi fi
# 编译 # 编译 libuv
echo "编译 uSockets..." compile_libuv() {
cd "$USOCKETS_DIR" echo "编译 libuv..."
make clean cd "$LIBUV_DIR"
rm -rf build 2>/dev/null || true
mkdir -p build
cd build
# 根据系统选择编译参数 if ! command -v cmake &> /dev/null; then
if [[ "$OSTYPE" == "darwin"* ]]; then echo "错误: 需要安装 cmake"
# macOS echo " macOS: brew install cmake"
if [[ $(uname -m) == "arm64" ]]; then echo " Linux: sudo apt install cmake 或 sudo yum install cmake"
# Apple Silicon echo " Windows: scoop install cmake 或 choco install cmake"
WITH_LIBUV=1 CFLAGS="-I/opt/homebrew/include" make exit 1
else
# Intel Mac
WITH_LIBUV=1 CFLAGS="-I/usr/local/include" make
fi fi
else
# Linux
WITH_LIBUV=1 make
fi
# 复制到 v-hono if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "mingw"* ]]; then
echo "复制库文件..." cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
cp "$USOCKETS_DIR/uSockets.a" "$SCRIPT_DIR/../lib/libusockets_full.a" else
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
fi
echo "=== 编译完成 ===" cmake --build . --config Release
echo "库文件: $SCRIPT_DIR/../lib/libusockets_full.a" }
# 编译 uSockets
compile_usockets() {
echo "编译 uSockets..."
cd "$USOCKETS_DIR"
rm -f *.o *.a 2>/dev/null || true
gcc -DLIBUS_NO_SSL -DLIBUS_USE_LIBUV -std=c11 -Isrc -I"$LIBUV_DIR/include" -O3 -c src/*.c src/eventing/*.c src/crypto/*.c
ar rcs uSockets.a *.o
rm -f *.o
}
# 合并库文件
merge_libraries() {
echo "合并库文件..."
rm -rf "$MERGE_DIR"
mkdir -p "$MERGE_DIR"
cd "$MERGE_DIR"
ar x "$USOCKETS_DIR/uSockets.a"
ar x "$LIBUV_DIR/build/libuv.a"
ar rcs "$OUTPUT_DIR/libusockets_full.a" *.o
rm -rf "$MERGE_DIR"
}
# 执行编译
compile_libuv
compile_usockets
merge_libraries
# 显示结果
LIB_SIZE=$(ls -lh "$OUTPUT_DIR/libusockets_full.a" | awk '{print $5}')
echo "" echo ""
echo "重新编译 v-hono 应用:" echo "=== 编译完成 ==="
echo " v -enable-globals -prod -o your_app your_app.v" echo "库文件: $OUTPUT_DIR/libusockets_full.a ($LIB_SIZE)"
echo ""
echo "编译 v-hono 应用:"
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "mingw"* ]]; then
echo " v -enable-globals -cc gcc -ldflags \"-ldbghelp\" -o app.exe app.v"
else
echo " v -enable-globals -prod -o app app.v"
fi
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16 -23
View File
@@ -2,41 +2,36 @@ module usockets
// 条件编译:根据操作系统选择正确的路径和库 // 条件编译:根据操作系统选择正确的路径和库
// @VMODROOT 指向包含 v.mod 的模块根目录 (v-hono/) // @VMODROOT 指向包含 v.mod 的模块根目录 (v-hono/)
// 预编译库按平台存放在 usockets/lib/{platform}/ 目录
$if windows { $if windows {
#flag -DLIBUS_USE_LIBUV #flag -DLIBUS_USE_LIBUV
#flag -DLIBUS_NO_SSL #flag -DLIBUS_NO_SSL
#flag -I@VMODROOT/usockets/include #flag -I@VMODROOT/usockets/include
#flag -L@VMODROOT/usockets/lib #flag -L@VMODROOT/usockets/lib/windows
#flag @VMODROOT/usockets/lib/libusockets_full.a #flag @VMODROOT/usockets/lib/windows/libusockets_full.a
#flag -lws2_32 -liphlpapi -lpsapi -luserenv -lole32 #flag -lws2_32 -liphlpapi -lpsapi -luserenv -lole32 -ldbghelp
} $else $if macos { } $else $if macos {
// macOS: 支持 Apple Silicon (M1/M2/M3) 和 Intel Mac
#flag -DLIBUS_USE_LIBUV #flag -DLIBUS_USE_LIBUV
#flag -DLIBUS_NO_SSL #flag -DLIBUS_NO_SSL
// libuv 路径 - 根据架构选择 Homebrew 路径
$if arm64 {
#flag -I/opt/homebrew/include
#flag -L/opt/homebrew/lib
} $else {
#flag -I/usr/local/include
#flag -L/usr/local/lib
}
// uSockets 库路径
#flag -I@VMODROOT/usockets/include #flag -I@VMODROOT/usockets/include
#flag -L@VMODROOT/usockets/lib
#flag @VMODROOT/usockets/lib/libusockets_full.a $if arm64 {
#flag -luv // Apple Silicon (M1/M2/M3)
#flag -L@VMODROOT/usockets/lib/macos-arm64
#flag @VMODROOT/usockets/lib/macos-arm64/libusockets_full.a
} $else {
// Intel Mac
#flag -L@VMODROOT/usockets/lib/macos-x64
#flag @VMODROOT/usockets/lib/macos-x64/libusockets_full.a
}
} $else { } $else {
// Linux 和其他平台 // Linux 和其他平台
#flag -DLIBUS_USE_LIBUV #flag -DLIBUS_USE_LIBUV
#flag -DLIBUS_NO_SSL #flag -DLIBUS_NO_SSL
#flag -I@VMODROOT/usockets/include #flag -I@VMODROOT/usockets/include
#flag -L@VMODROOT/usockets/lib #flag -L@VMODROOT/usockets/lib/linux
#flag @VMODROOT/usockets/lib/libusockets_full.a #flag @VMODROOT/usockets/lib/linux/libusockets_full.a
#flag -luv
} }
#include "libusockets.h" #include "libusockets.h"
@@ -105,8 +100,6 @@ pub fn (ctx SocketContext) on_writable(h voidptr) { C.us_socket_context_on_writa
pub fn (ctx SocketContext) on_timeout(h voidptr) { C.us_socket_context_on_timeout(0, ctx, h) } pub fn (ctx SocketContext) on_timeout(h voidptr) { C.us_socket_context_on_timeout(0, ctx, h) }
pub fn (ctx SocketContext) on_end(h voidptr) { C.us_socket_context_on_end(0, ctx, h) } pub fn (ctx SocketContext) on_end(h voidptr) { C.us_socket_context_on_end(0, ctx, h) }
pub fn (ctx SocketContext) listen(port int) ListenSocket { pub fn (ctx SocketContext) listen(port int) ListenSocket {
// 参数: ssl=0, context, host=nil, port, options=LIBUS_LISTEN_DEFAULT(0), socket_ext_size=0
// 注意: backlog 是在 uSockets 库内部硬编码的,不通过此函数传递
return C.us_socket_context_listen(0, ctx, unsafe { nil }, port, 0, 0) return C.us_socket_context_listen(0, ctx, unsafe { nil }, port, 0, 0)
} }
+1 -1
View File
@@ -1,7 +1,7 @@
Module { Module {
name: 'hono' name: 'hono'
description: 'A high-performance V language web framework inspired by Hono.js, featuring hybrid routing, LRU cache, middleware support, and more.' description: 'A high-performance V language web framework inspired by Hono.js, featuring hybrid routing, LRU cache, middleware support, and more.'
version: '0.7.2' version: '0.7.4'
license: 'MIT' license: 'MIT'
dependencies: [] dependencies: []
} }