You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libuv:多线程事件循环处理TCP连接的示例及进程线程选型咨询

libuv 多线程事件循环处理TCP连接及进程/线程选型问题

1. 单线程对应单事件循环的TCP处理示例

核心思路是:主线程负责监听端口并接收新连接,将TCP句柄轮询分配给预先创建的工作线程,每个工作线程运行独立的事件循环,处理对应连接的读写逻辑。以下是可运行的示例代码:

#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define WORKER_THREAD_COUNT 4

typedef struct {
    uv_loop_t* loop;
    uv_mutex_t mutex;
    uv_async_t async;
    uv_tcp_t* client_handle;
} worker_data_t;

worker_data_t workers[WORKER_THREAD_COUNT];
int next_worker = 0;

void on_client_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
    if (nread > 0) {
        // 回显客户端数据
        uv_write_t* req = malloc(sizeof(uv_write_t));
        uv_buf_t res_buf = uv_buf_init(buf->base, nread);
        uv_write(req, stream, &res_buf, 1, NULL);
    } else if (nread < 0) {
        if (nread != UV_EOF) {
            fprintf(stderr, "读取错误: %s\n", uv_strerror(nread));
        }
        uv_close((uv_handle_t*)stream, NULL);
    }
    if (buf->base) {
        free(buf->base);
    }
}

void on_client_connected(uv_stream_t* server, int status) {
    if (status < 0) {
        fprintf(stderr, "连接错误: %s\n", uv_strerror(status));
        return;
    }

    uv_tcp_t* client = malloc(sizeof(uv_tcp_t));
    uv_tcp_init(uv_default_loop(), client);
    if (uv_accept(server, (uv_stream_t*)client) == 0) {
        // 轮询选择工作线程
        worker_data_t* worker = &workers[next_worker];
        next_worker = (next_worker + 1) % WORKER_THREAD_COUNT;

        // 线程安全传递句柄
        uv_mutex_lock(&worker->mutex);
        worker->client_handle = client;
        uv_mutex_unlock(&worker->mutex);

        // 通知工作线程处理新连接
        uv_async_send(&worker->async);
    } else {
        uv_close((uv_handle_t*)client, NULL);
        free(client);
    }
}

void worker_async_cb(uv_async_t* async) {
    worker_data_t* data = (worker_data_t*)async->data;
    uv_mutex_lock(&data->mutex);
    uv_tcp_t* client = data->client_handle;
    data->client_handle = NULL;
    uv_mutex_unlock(&data->mutex);

    if (client) {
        // 将客户端句柄转移到工作线程的事件循环
        uv_handle_set_loop((uv_handle_t*)client, data->loop);
        uv_read_start((uv_stream_t*)client, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
            buf->base = malloc(suggested_size);
            buf->len = suggested_size;
        }, on_client_read);
    }
}

void* worker_thread(void* arg) {
    worker_data_t* data = (worker_data_t*)arg;
    data->loop = uv_loop_new();

    // 初始化异步句柄,用于主线程与工作线程通信
    uv_async_init(data->loop, &data->async, worker_async_cb);
    data->async.data = data;

    uv_mutex_init(&data->mutex);

    // 启动工作线程的事件循环
    uv_run(data->loop, UV_RUN_DEFAULT);

    // 资源清理
    uv_mutex_destroy(&data->mutex);
    uv_loop_delete(data->loop);
    return NULL;
}

int main() {
    uv_loop_t* main_loop = uv_default_loop();
    uv_tcp_t server;
    struct sockaddr_in addr;

    // 创建并启动工作线程
    for (int i = 0; i < WORKER_THREAD_COUNT; i++) {
        uv_thread_t thread;
        uv_thread_create(&thread, worker_thread, &workers[i]);
    }

    // 初始化监听服务器
    uv_tcp_init(main_loop, &server);
    uv_ip4_addr("0.0.0.0", 8080, &addr);
    uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);

    int r = uv_listen((uv_stream_t*)&server, 128, on_client_connected);
    if (r) {
        fprintf(stderr, "监听错误: %s\n", uv_strerror(r));
        return 1;
    }

    return uv_run(main_loop, UV_RUN_DEFAULT);
}

代码关键说明:

  • 启动4个工作线程,每个线程持有独立的uv_loop_t实例
  • 主线程通过uv_async_t向工作线程发送新连接通知,保证线程安全
  • 工作线程将TCP句柄转移到自身事件循环后,启动读操作处理客户端请求

2. 多进程vs多线程的选型问题

nginx选择多进程架构,核心原因在于生产环境的稳定性需求:

  • 强隔离性:单个进程崩溃不会波及其他进程,避免线程模型中因单个线程异常导致整个进程挂掉的风险;进程间内存完全独立,内存泄漏、竞态条件的影响范围被限制。
  • 权限管控灵活:主进程以root权限运行(用于绑定80/443等低端口),子进程切换为普通用户权限,降低被攻击后的风险。
  • 平滑升级友好:多进程架构可以通过逐步替换子进程实现热重启,不中断服务。
  • Linux调度优势:Linux对进程调度的优化非常成熟,fork进程的开销在现代系统中极低,进程调度的性能和线程差异不大。

但多线程并非没有优势:

  • 内存共享高效:线程共享进程内存空间,无需IPC即可传递数据,适合需要高频数据交互的场景。
  • 资源开销更低:线程的创建、销毁开销远低于进程,内存占用也更少。

libuv官方示例多用多进程,本质是因为服务器场景下多进程的稳定性更符合生产标准。但如果你的场景对资源开销、通信效率要求更高,多线程架构完全可行——只要遵守libuv的跨线程句柄操作规则,做好线程安全控制即可。

内容的提问来源于stack exchange,提问作者Wad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 00:06:22