ETJava Beta | Java    注册   登录
  • 搜索:
  • 使用Boost.asio与Boost.beast基于协程连接ws

    发表于      阅读(1)     博客类别:Crawler     转自:https://www.cnblogs.com/ink19/p/18538084/boost_asio_coroutine
    如有侵权 请联系我们删除  (页面底部联系我们)  

    目录

    前言

    本文主要介绍一个使用Boost.asio和Boost.beast基于协程连接Websocket(ws)的方法。其中C++版本为20,Boost版本为1.82。

    准备工作

    首先需要构造一个最基本的ws服务器用于测试。
    本文使用nodejs构造了一个简单的ws服务器,基于ws库。

    const WebSocket = require('ws');
    
    const wss = new WebSocket.Server({ port: 8080 });
    
    wss.on('connection', function connection(ws) {
      console.log('New client connected')
      ws.on('message', function incoming(message) {
        console.log('received: %s', message);
        ws.send(message);
      });
    });
    
    console.log('WebSocket server is running on port 8080');
    

    实现

    初始化io_context并监听信号

    boost::asio::io_context io_context;
    boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
    signals.async_wait([&](auto, auto){ io_context.stop(); });
    

    启动连接ws的线程并启动io_context

    boost::asio::co_spawn(io_context, ws, boost::asio::detached);
    io_context.run();
    

    其中ws的签名为boost::asio::awaitable<void> ws()

    建立tcp链接(以下步骤皆位于ws函数中)

    这一步可以分为两个步骤,解析dns以及建立tcp链接。

    auto executor = co_await boost::asio::this_coro::executor;
    boost::asio::ip::tcp::socket socket(executor);
    boost::asio::ip::tcp::resolver resolver(executor);
    
    // 如果不使用dns解析,也可以直接使用以下直接代替
    // boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 8080)
    auto point = co_await resolver.async_resolve("localhost", "8080", boost::asio::use_awaitable);
    
    co_await socket.async_connect(
      point->endpoint(), 
      boost::asio::use_awaitable);
    

    ws握手

    先使用boost::beast::websocket::stream<boost::asio::ip::tcp::socket&>包装,然后进行握手。

    boost::beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(socket);
    co_await ws.async_handshake("127.0.0.1", "/", boost::asio::use_awaitable);
    

    握手过程中发送的信息类似于

    GET / HTTP/1.1
    Host: www.example.com
    Upgrade: websocket
    Connection: upgrade
    Sec-WebSocket-Key: 2pGeTR0DsE4dfZs2pH+8MA==
    Sec-WebSocket-Version: 13
    User-Agent: Boost.Beast/216
    

    传输数据

    boost::asio::steady_timer timer(executor);
    for (;;) {
      co_await ws.async_write(boost::asio::buffer("hello"), boost::asio::use_awaitable);
      std::cout << "send: hello" << std::endl;
      
      boost::beast::flat_buffer buffer;
      co_await ws.async_read(buffer, boost::asio::use_awaitable);
      std::cout << boost::format("recv: %s") % std::string((char *)buffer.data().data(), buffer.data().size()) << std::endl;
      
      timer.expires_after(std::chrono::seconds(1));
      co_await timer.async_wait(boost::asio::use_awaitable);
    }
    

    效果

    效果图

    总结

    有了协程之后,boost感觉好用多了