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

Boost::asio WebSocket问题:tcp::no_delay无效,客户端接收消息拼接

问题解决思路

核心原因

你复用了同一个beast::flat_buffer对象m_WriteBuffer,在第一次async_write还未完成时,就再次通过ostream往里面写入新数据,导致两次消息内容被合并到同一个buffer里,最终WebSocket发送的是合并后的帧。

Sleep(100)能临时解决,是因为它让第一次异步write有足够时间完成,buffer在第二次写入前已经处于可用状态,但这是不可靠的临时方案。而tcp::no_delay(true)是禁用TCP Nagle算法,解决的是TCP层的小包合并问题,但你的问题是应用层buffer复用导致的内容合并,和TCP层无关,所以设置它没用。

修复方案

方案一:每次发送使用独立的buffer

不要复用同一个flat_buffer,每次发送消息时创建新的buffer对象,确保每次write的是独立的消息内容。修改后的发送代码示例:

// 每次发送创建新的flat_buffer,用智能指针管理生命周期
auto write_buffer = std::make_shared<beast::flat_buffer>();
boost::beast::ostream(*write_buffer) << message;
ws_.async_write(write_buffer->data(),
            beast::bind_front_handler(
                &WebSocketSession::on_write,
                shared_from_this(),
                write_buffer)); // 传递智能指针,确保buffer存活到write完成

需要同步调整on_write函数,接收这个buffer的智能指针参数,避免buffer提前被销毁。

方案二:维护发送队列确保顺序发送

添加一个消息队列,当有新消息要发送时,如果当前没有正在执行的write操作就立即发送;否则将消息加入队列,等上一次on_write完成后再发送队列里的下一条消息。示例思路:

// 类成员变量
std::queue<std::string> m_send_queue;
bool m_is_writing = false;

// 对外暴露的发送接口
void send(std::string message) {
    bool was_empty = m_send_queue.empty();
    m_send_queue.push(std::move(message));
    if (was_empty && !m_is_writing) {
        do_write();
    }
}

// 实际执行发送的函数
void do_write() {
    m_is_writing = true;
    auto& curr_msg = m_send_queue.front();
    auto write_buffer = std::make_shared<beast::flat_buffer>();
    boost::beast::ostream(*write_buffer) << curr_msg;
    ws_.async_write(write_buffer->data(),
                beast::bind_front_handler(
                    &WebSocketSession::on_write,
                    shared_from_this(),
                    write_buffer));
}

// write完成后的回调处理
void on_write(boost::system::error_code ec, std::size_t bytes_transferred, std::shared_ptr<beast::flat_buffer>) {
    // 处理错误逻辑
    if (ec) {
        // 错误处理代码
        return;
    }
    // 清理已发送的消息,继续发送队列中的下一条
    m_send_queue.pop();
    m_is_writing = false;
    if (!m_send_queue.empty()) {
        do_write();
    }
}

额外提示

  • WebSocket本身是基于帧的协议,只要你正确发送每个独立的帧,客户端就能收到独立的消息,无需依赖TCP层的设置。
  • 异步操作中必须注意资源生命周期,用智能指针管理buffer等资源,避免因对象提前销毁导致的未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:22:40