Boost Beast websocket 服务器异步接受失败,缓冲区溢出

Posted

技术标签:

【中文标题】Boost Beast websocket 服务器异步接受失败,缓冲区溢出【英文标题】:Boost beast websocket server async accept failed, buffer overflow 【发布时间】:2019-06-21 09:15:48 【问题描述】:

我通过 boost asio websocket 编写了一个 websocket 服务器。 当我尝试将它与 chrome 连接时,它总是说连接失败。 并且日志显示缓冲区溢出。 尤其是在我打开很多网站之后。

[2019-06-21 16:40:45.071345]-[0x00003130]-[error]:[NormalSession.cpp:75] 接受器异步接受失败,ec = beast.http:7,msg = 缓冲区溢出

void NormalSession::run() 
    auto sp = shared_from_this();
    ws_->async_accept(boost::asio::bind_executor(*strand_, [&,sp](boost::system::error_code ec) 
        if (ec) 
            LOG_ERR << "acceptor async accept failed, ec = " << ec<<", msg = "<<ec.message();
            return;
        

        process();
    ));



var ws=new WebSocket("ws://127.0.0.1:12802");
ws.onopen=()=>console.log('ws open');
ws.onclose=()=>console.log('ws close');
ws.onmessage=(msg)=>console.log('ws onMessage');console.log(msg);

那么为什么缓冲区溢出呢?以及如何解决?


完整代码

iListener.h

class iListener: public std::enable_shared_from_this<iListener>  
public:

    iListener(const std::string &, unsigned short , boost::asio::io_context& );

    ~iListener();

public:
    void run();
protected:

    virtual void do_accept()=0;

protected:
    boost::asio::ip::tcp::acceptor *acceptor_=NULL;
;

iListener.cpp

iListener::iListener(const std::string &addressStr, unsigned short port, boost::asio::io_context &ioc) 

    acceptor_ = NULL;


    auto const address = boost::asio::ip::make_address(addressStr);

    acceptor_ = new boost::asio::ip::tcp::acceptor(ioc);
    boost::asio::ip::tcp::endpoint endpointaddress, port;
    boost::system::error_code ec;

    // Open the acceptor
    acceptor_->open(endpoint.protocol(), ec);
    if (ec) 
        LOG_ERR << "acceptor open failed, ec = " << ec << ", msg = " << ec.message();
        return;

    

    // Allow address reuse
    acceptor_->set_option(boost::asio::socket_base::reuse_address(true), ec);
    if (ec) 
        LOG_ERR << "acceptor set option failed, ec = " << ec << ", msg = " << ec.message();
        return;
    

    // Bind to the server address
    acceptor_->bind(endpoint, ec);
    if (ec) 
        LOG_ERR << "acceptor bind failed, ec = " << ec << ", msg = " << ec.message();
        return;
    

    // Start listening for connections
    acceptor_->listen(boost::asio::socket_base::max_listen_connections, ec);
    if (ec) 
        LOG_ERR << "acceptor listen failed, ec = " << ec << ", msg = " << ec.message();
        return;
    



iListener::~iListener() 
    delete acceptor_;
    acceptor_ = NULL;


void iListener::run() 
    if (!acceptor_->is_open()) 
        return;
    
    do_accept();


NormalListener.h

class NormalListener:public iListener 
public:
    NormalListener(const std::string &addressStr, unsigned short port, boost::asio::io_context& ioc);
    ~NormalListener();
private:
    void do_accept();
private:
;

NormalListener.cpp

NormalListener::NormalListener(const std::string &addressStr, unsigned short port,  boost::asio::io_context& ioc):iListener(addressStr, port, ioc) 




NormalListener::~NormalListener() 




void NormalListener::do_accept() 
    auto sp = shared_from_this();
    acceptor_->async_accept([&,sp](const boost::system::error_code& ec, boost::asio::ip::tcp::socket peer) 
        if (ec) 
            LOG_ERR << "acceptor async accept failed, ec = " << ec<<", msg = "<<ec.message();
            return;
        
        else 
            // Create the session and run it
            std::make_shared<NormalSession>(std::move(peer))->run();

        
        do_accept();
    );


iSession.hpp

template<typename T>
class iSession : public std::enable_shared_from_this<iSession<T>> 

public:
    iSession() 
        ws_ = NULL;
        strand_ = NULL;
        buffer_ = new boost::beast::multi_buffer();
    

    ~iSession() 
        delete buffer_;
        buffer_ = NULL;
        delete strand_;
        strand_ = NULL;
        delete ws_;
        ws_ = NULL;

    

public:
    boost::beast::websocket::stream<T> *ws_ = NULL;
    boost::asio::strand<boost::asio::io_context::executor_type> *strand_ = NULL;
    boost::beast::multi_buffer *buffer_ = NULL;


public:
    void virtual run() = 0;

protected:
    void process()        
    



private:


protected:

;

#endif //ESDK_MSP_ISESSION_HPP

NormalSession.h

class NormalSession : public iSession<boost::asio::ip::tcp::socket> 
public:
    NormalSession(boost::asio::ip::tcp::socket);

    ~NormalSession();

public:
    void run();

protected:

;

NormalSession.cpp

NormalSession::NormalSession(boost::asio::ip::tcp::socket socket)
    ws_ = new boost::beast::websocket::stream<boost::asio::ip::tcp::socket>(std::move(socket));
    strand_ = new boost::asio::strand<boost::asio::io_context::executor_type>(ws_->get_executor());


NormalSession::~NormalSession() 



void NormalSession::run() 
    auto sp = shared_from_this();
    ws_->async_accept(boost::asio::bind_executor(*strand_, [&,sp](boost::system::error_code ec) 
        if (ec) 
            LOG_ERR << "acceptor async accept failed, ec = " << ec<<", msg = "<<ec.message();
            return;
        

        process();
    ));



【问题讨论】:

您发布的代码中的缓冲区在哪里?发布完整代码(或它的模拟) @Explorer_N 抱歉回复你太晚了,我还没有设置缓冲区..请看我现在编辑的代码。 在此之前,我认为您需要更正一下标题,因为我认为没有所谓的“Boost asio websocket”这种东西。我发现您正在使用 Boost.Beast。 @vainman 另外一件让我烦恼的事情是,为什么接受抛出“缓冲区溢出”,你认为接受需要缓冲区吗? @Explorer_N 我不知道,可能是 http 缓冲区?需要 chrome 的 CA 吗? 【参考方案1】:

这在文档中有解释:

如果请求大小超过流内部的容量 缓冲区,将指示错误websocket::buffer_overflow。到 处理更大的请求,应用程序应该读取 HTTP 请求 直接使用http::async_read,然后将请求传递给 websocket::stream::accept 的适当过载或 websocket::stream::async_accept

见: https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/ref/boost__beast__websocket__stream/async_accept/overload1.html

【讨论】:

感谢您的回答,但是当我尝试使用http::async_read时,总是出现error_code 995,IO线程已经退出。有什么样品或建议吗? 现在我使用 http::async_read 和 websocket::stream::async_accept ,它在 ws 中运行良好,但在 wss 中无法运行。 wss中如何使用? 是的,我终于找到了解决办法,谢谢你的提示

以上是关于Boost Beast websocket 服务器异步接受失败,缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章

Boost Beast websocket 服务器异步接受失败,缓冲区溢出

Boost :: Beast Websocket双向流(C ++)

如何正确写c++ boost beast websocket server

如何从另一个线程中断 websocket(使用 boost beast)?

Boost Beast 将带有字节数组的 json 发送到客户端抛出 websocket

关于 boost beast websocket api : async_close, async_write