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

基于Boost WebSocket示例客户端,如何添加事件并输出消息结果?

实现Boost WebSocket客户端的事件驱动处理(类似socket.io的socket.on)

你已经搞定了Boost WebSocket的连接,接下来要实现类似socket.io的事件监听,核心思路是自己封装一个事件订阅-分发机制——因为Boost WebSocket本身只提供基础的消息收发能力,没有内置的事件系统。咱们一步步来实现:

1. 先约定消息格式

socket.io的事件本质是带标识的结构化消息,所以咱们得先和服务端约定好消息格式,最通用的方式是用JSON封装事件名和数据,比如:

{"event": "SomeEvent", "data": "Hello from server!"}

这样客户端收到消息后,就能解析出对应的事件名和数据,再触发对应的回调逻辑。

2. 封装事件处理器类

咱们写一个轻量的EventHandler类,用来管理事件的订阅和触发,模拟socket.io的on/emit逻辑:

#include <unordered_map>
#include <vector>
#include <functional>
#include <nlohmann/json.hpp> // 用这个流行的JSON库解析消息,直接下载头文件即可使用

using json = nlohmann::json;
using EventCallback = std::function<void(const json&)>;

class EventHandler {
public:
    // 订阅事件,对应socket.io的socket.on
    void on(const std::string& event_name, EventCallback callback) {
        m_event_map[event_name].push_back(std::move(callback));
    }

    // 触发事件,收到对应消息时调用
    void emit(const std::string& event_name, const json& data) {
        auto it = m_event_map.find(event_name);
        if (it != m_event_map.end()) {
            // 遍历所有订阅该事件的回调并执行
            for (const auto& callback : it->second) {
                callback(data);
            }
        }
    }

private:
    // 存储事件名到回调列表的映射
    std::unordered_map<std::string, std::vector<EventCallback>> m_event_map;
};

3. 集成到Boost WebSocket客户端

把事件处理器和Boost WebSocket的消息接收逻辑结合起来,修改你已有的客户端代码:

#include <boost/beast.hpp>
#include <boost/asio.hpp>
#include <iostream>

namespace beast = boost::beast;
namespace websocket = beast::websocket;
namespace net = boost::asio;
using tcp = boost::asio::ip::tcp;

class WsClient {
public:
    WsClient(net::io_context& ioc, tcp::resolver::results_type endpoints)
        : m_ws(ioc) {
        connect(endpoints);
    }

    // 对外暴露事件订阅接口,让外部可以像socket.io一样调用
    void on(const std::string& event, EventCallback callback) {
        m_event_handler.on(event, callback);
    }

private:
    websocket::stream<tcp::socket> m_ws;
    beast::flat_buffer m_buffer;
    EventHandler m_event_handler;

    void connect(tcp::resolver::results_type endpoints) {
        net::async_connect(m_ws.next_layer(), endpoints,
            [this](beast::error_code ec, tcp::endpoint) {
                if (ec) {
                    std::cerr << "连接失败: " << ec.message() << std::endl;
                    return;
                }
                // 执行WebSocket握手
                m_ws.async_handshake("localhost", "/",
                    [this](beast::error_code ec) {
                        if (ec) {
                            std::cerr << "握手失败: " << ec.message() << std::endl;
                            return;
                        }
                        // 握手成功后开始监听消息
                        receive_message();
                    });
            });
    }

    void receive_message() {
        m_ws.async_read(m_buffer,
            [this](beast::error_code ec, std::size_t bytes_transferred) {
                boost::ignore_unused(bytes_transferred);
                if (ec) {
                    std::cerr << "读取消息失败: " << ec.message() << std::endl;
                    return;
                }
                // 把收到的二进制消息转换成字符串
                std::string msg = beast::buffers_to_string(m_buffer.data());
                m_buffer.consume(m_buffer.size()); // 清空缓冲区准备下一次接收

                try {
                    // 解析JSON格式的消息
                    json parsed_msg = json::parse(msg);
                    std::string event_name = parsed_msg["event"];
                    json event_data = parsed_msg["data"];

                    // 触发对应的事件回调,把数据传给订阅者
                    m_event_handler.emit(event_name, event_data);
                } catch (const std::exception& e) {
                    std::cerr << "解析消息出错: " << e.what() << std::endl;
                }

                // 递归调用,持续监听下一条消息
                receive_message();
            });
    }
};

4. 最终使用示例

现在你就可以像用socket.io那样订阅事件,把消息输出到控制台了:

int main() {
    try {
        net::io_context ioc;
        tcp::resolver resolver(ioc);
        // 替换成你的服务端地址和端口
        auto endpoints = resolver.resolve("localhost", "8080");

        WsClient client(ioc, endpoints);

        // 订阅SomeEvent事件,收到消息后打印到控制台
        client.on("SomeEvent", [](const json& data) {
            std::cout << "收到SomeEvent事件: " << data.dump() << std::endl;
        });

        // 可以订阅多个不同的事件
        client.on("ChatMessage", [](const json& data) {
            std::cout << "新聊天消息: " << data["content"] << std::endl;
        });

        // 启动IO循环,等待事件触发
        ioc.run();
    } catch (const std::exception& e) {
        std::cerr << "程序出错: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

额外提示

  • 如果不想用JSON,也可以自定义简单的分隔格式(比如用|分隔事件名和数据),但JSON的扩展性更好;
  • 可以给EventHandler扩展更多功能,比如取消订阅(类似socket.off)、只触发一次的事件(类似socket.once),只需要在映射里管理回调的生命周期即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:35:15