【问题标题】:Websocket client in C++ using boost::Beast - throwing error at write operationC++ 中的 Websocket 客户端使用 boost::Beast - 在写操作时抛出错误
【发布时间】:2020-05-12 15:53:33
【问题描述】:

下面是一段代码,我正在努力使其成功。我使用 git hub https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/quick_start/websocket_client.html 提供的参考代码。 问题是当我调用 connect 方法并在同一个函数中执行写入操作时,它可以工作,但是如果我将它放在不同的函数中,它将无法工作。

我是boost和shared_pointer的新手,如果我没有任何意义,请原谅。

    // Sends a WebSocket message and prints the response
    class CWebSocket_Sync : public std::enable_shared_from_this<CWebSocket_Sync>
    {
        tcp::resolver resolver_;
        websocket::stream<tcp::socket> ws_;
        boost::beast::multi_buffer buffer_;
        std::string host_;
        std::string text_;

    public:
        // Resolver and socket require an io_context
        explicit
            CWebSocket_Sync(boost::asio::io_context& ioc)
            : resolver_(ioc)
            , ws_(ioc)
        {
        }

        void 
            connect(
                char const* host,
                char const* port,
                char const* text)
        {
            // Save these for later
            host_ = host;
            text_ = text;

            // Look up the domain name
            auto const results = resolver_.resolve(host, port);

            // Make the connection on the IP address we get from a lookup
            auto ep = net::connect(ws_.next_layer(), results);

            // Update the host_ string. This will provide the value of the
            // Host HTTP header during the WebSocket handshake.
            // See https://tools.ietf.org/html/rfc7230#section-5.4
            host_ += ':' + std::to_string(ep.port());

            // Perform the websocket handshake
            ws_.handshake(host_, "/");

            //ws_.write(net::buffer(std::string(text)));
            //// This buffer will hold the incoming message
            //beast::flat_buffer buffer;

            //// Read a message into our buffer
            //ws_.read(buffer);


        }

        void ServerCommand(char const* text)
        {
            ws_.write(net::buffer(std::string(text)));   // <-- this line throw memory error 

            // This buffer will hold the incoming message
            beast::flat_buffer buffer;

            // Read a message into our buffer
            ws_.read(buffer);


            // The make_printable() function helps print a ConstBufferSequence
            std::cout << beast::make_printable(buffer.data()) << std::endl;
        }

        void CloseConnection()
        {
            // Close the WebSocket connection
            ws_.close(websocket::close_code::normal);
        }

    };
int main(int argc, char** argv)
{
    auto const host = "127.0.0.1";
    auto const port = "7011";
    auto const loginCmd = "login"
    boost::asio::io_context ioc;

    std::make_shared<CWebSocket_Sync>(ioc)->connect(host, port, loginCmd);

    std::make_shared<CWebSocket_Sync>(ioc)->ServerCommand(loginCmd);

    std::make_shared<CWebSocket_Sync>(ioc)->CloseConnection();

    return EXIT_SUCCESS;
}

【问题讨论】:

    标签: c++ websocket boost-asio shared-ptr boost-beast


    【解决方案1】:
    std::make_shared<CWebSocket_Sync>(ioc)->connect(host, port);
    std::make_shared<CWebSocket_Sync>(ioc)->ServerCommand(loginCmd);
    std::make_shared<CWebSocket_Sync>(ioc)->CloseConnection();
    

    每一行都会创建一个新客户端 (make_shared&lt;CWebSocket_Sync&gt;) 并在其上运行一个步骤。你可能想要什么:

    auto client = std::make_shared<CWebSocket_Sync>(ioc);
    client->connect(host, port);
    client->ServerCommand(loginCmd);
    client->CloseConnection();
    

    确实有效:

    #include <boost/beast.hpp>
    #include <boost/beast/websocket.hpp>
    #include <memory>
    #include <iostream>
    
    namespace net       = boost::asio;
    namespace beast     = boost::beast;
    namespace websocket = beast::websocket;
    using net::ip::tcp;
    
    // Sends a WebSocket message and prints the response
    class CWebSocket_Sync : public std::enable_shared_from_this<CWebSocket_Sync> {
        tcp::resolver resolver_;
        websocket::stream<tcp::socket> ws_;
        boost::beast::multi_buffer buffer_;
        std::string host_;
    
    public:
        // Resolver and socket require an io_context
        explicit CWebSocket_Sync(boost::asio::io_context& ioc)
            : resolver_(ioc), ws_(ioc) { }
    
        void connect(char const* host, char const* port) {
            // Save these for later
            host_ = host;
    
            // Look up the domain name
            auto const results = resolver_.resolve(host, port);
    
            // Make the connection on the IP address we get from a lookup
            auto ep = net::connect(ws_.next_layer(), results);
    
            // Update the host_ string. This will provide the value of the
            // Host HTTP header during the WebSocket handshake.
            // See https://tools.ietf.org/html/rfc7230#section-5.4
            host_ += ':' + std::to_string(ep.port());
    
            // Perform the websocket handshake
            ws_.handshake(host_, "/");
        }
    
        void ServerCommand(char const* text) {
            ws_.write(net::buffer(std::string(text)));   // <-- this line throw memory error 
    
            beast::flat_buffer buffer;
            ws_.read(buffer);
    
            std::cout << beast::make_printable(buffer.data()) << std::endl;
        }
    
        void CloseConnection() {
            ws_.close(websocket::close_code::normal);
        }
    };
    
    int main() {
        auto const host = "127.0.0.1";
        auto const port = "7011";
        auto const loginCmd = "login";
        boost::asio::io_context ioc;
    
        auto client = std::make_shared<CWebSocket_Sync>(ioc);
        client->connect(host, port);
        client->ServerCommand(loginCmd);
        client->CloseConnection();
    }
    

    简化

    但是,既然没有使用共享生命周期,而且您没有在任何地方使用异步调用,为什么不简单:

    Live On Coliru

    class CWebSocket_Sync {
    

    及以后:

        CWebSocket_Sync client(ioc);
        client.connect(host, port);
        client.ServerCommand(loginCmd);
        client.CloseConnection();
    

    【讨论】:

    • 非常感谢。它真的像一个魅力。您能否指导我如何了解有关此 C++ boost::asio 编程的更多信息。我尝试了不同的门户和视频,但没有找到任何可以简单解释的内容。感谢您的回答。
    • 我认为野兽教程是最好的。
    • 我喜欢你的例子,因为它比官方文档简单得多,又短又甜。但是,如果服务器一个接一个地发回 2/3 消息;您的代码只会读取 1(第一个)。如何一次读回所有消息?很抱歉这个新手问题,刚刚熟悉 Boost。
    • 你是什么意思,2/3 如 0.666666... 消息?还是两三个?我认为第一个不可能发生。在另一种情况下,您只会阅读多条消息,对吗?例如。 coliru.stacked-crooked.com/a/5336ed12cbf15f43
    • @Mecanik 忘了@提及你^
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2018-09-05
    • 2019-02-27
    • 2020-09-02
    • 2010-12-24
    相关资源
    最近更新 更多