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

基于C++/libuv的TCP进程间通信问题:on_read函数未触发

问题:libuv TCP服务器on_read回调未触发,客户端消息已发送

我实现了基于libuv的客户端-服务器TCP通信程序,服务器后台运行后,客户端能成功建立TCP连接并发送消息(Wireshark已确认数据包已发出),但服务器的on_read函数始终未被调用,无法在屏幕上打印客户端发送的消息。

服务器代码

#include <uv.h>
#include <iostream>

void on_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf)
{
    std::cout << "ANY DATA?\n";

    if(nread > 0)
    {
        std::cout << "Received: " << std::string(buf->base, nread) << std::endl;
    }
    else if(nread < 0)
    {
        uv_close((uv_handle_t*)client, NULL);
    }
    free(buf->base);
}

void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
    buf->base = (char*)malloc(suggested_size);
    buf->len = suggested_size;
}

void on_new_connection(uv_stream_t* server, int status)
{
    if(status < 0)
    {
        std::cerr << "Error on_new_connection: " << uv_strerror(status) << std::endl;
        return;
    }

    uv_tcp_t* client = new uv_tcp_t();
    uv_tcp_init(uv_default_loop(), client);

    if(uv_accept(server, (uv_stream_t*)client) < 0)
    {
        uv_close((uv_handle_t*)client, NULL);
        return;
    }
    
    std::cout << "New connection accepted." << std::endl;
    uv_read_start((uv_stream_t*)&client, alloc_buffer, on_read);
}

int main()
{
    uv_tcp_t server;
    uv_tcp_init(uv_default_loop(), &server);

    struct sockaddr_in bind_addr;
    uv_ip4_addr("0.0.0.0", 7000, &bind_addr);

    if(int r = uv_tcp_bind(&server, (const struct sockaddr*)&bind_addr, 0); r < 0)
    {
        std::cerr << "Error binding server: " << uv_strerror(r) << std::endl;
        return 1;
    }

    if(int r = uv_listen((uv_stream_t*)&server, 128, on_new_connection); r < 0)
    {
        std::cerr << "Error starting server: " << uv_strerror(r) << std::endl;
        return 1;
    }

    std::cout << "Server started on port 7000." << std::endl;

    uv_run(uv_default_loop(), UV_RUN_DEFAULT);

    return 0;
}

客户端代码

#include <uv.h>
#include <iostream>

void after_send(uv_write_t *req, int status)
{
    std::cout << status << "as\n";
}

void on_connect(uv_connect_t* req, int status)
{
    if(status < 0)
    {
        std::cerr << "Error on_connect: " << uv_strerror(status) << std::endl;
        return;
    }

    std::cout << "Connected to server." << std::endl;

    Sleep(1000);

    uv_buf_t buf = uv_buf_init("Hello, server!\r\n", 14);
    uv_write_t write_req;
    uv_write(&write_req, req->handle, &buf, 1, after_send);
}

int main()
{
    uv_tcp_t client;
    uv_tcp_init(uv_default_loop(), &client);

    struct sockaddr_in serv_addr;
    uv_ip4_addr("127.0.0.1", 7000, &serv_addr);

    uv_connect_t connect_req;
    uv_tcp_connect(&connect_req, &client, (const struct sockaddr*)&serv_addr, on_connect);

    return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}

问题分析与修复

核心问题

服务器on_new_connection函数中,uv_read_start的参数传递错误:

// 错误写法:传递了指针的地址,类型不匹配
uv_read_start((uv_stream_t*)&client, alloc_buffer, on_read);

这里client是uv_tcp_t*类型的指针,错误地取了它的地址(&client)并转换为uv_stream_t*,导致libuv无法正确识别这个TCP客户端句柄,因此不会触发读回调。

修复代码

将uv_read_start的调用改为直接传递client指针(uv_tcp_t继承自uv_stream_t,可以直接转换):

// 正确写法:传递客户端句柄指针
uv_read_start((uv_stream_t*)client, alloc_buffer, on_read);

额外优化建议

  1. 内存泄漏修复:服务器中用new创建的uv_tcp_t* client需要在连接关闭时释放,避免内存泄漏。修改on_read的关闭分支:
else if(nread < 0)
{
    uv_close((uv_handle_t*)client, [](uv_handle_t* handle) {
        delete (uv_tcp_t*)handle;
    });
}
  1. 跨平台兼容性:客户端中的Sleep(1000)是Windows特有的API,建议替换为libuv的跨平台函数uv_sleep(1000)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:23:11