Boost beast websocket 服务器异步接受失败,缓冲区溢出
Boost beast websocket server async accept failed, buffer overflow
我通过 boost asio websocket 编写了一个 websocket 服务器。
当我尝试用 chrome 连接它时,它总是说连接失败。
日志显示缓冲区溢出。
尤其是在我打开了很多网站之后。
[2019-06-21 16:40:45.071345]-[0x00003130]-[error]:[NormalSession.cpp:75] acceptor 异步接受失败,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 endpoint{address, 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();
}));
}
这在文档中有解释:
If the request size exceeds the capacity of the stream's internal
buffer, the error websocket::buffer_overflow
will be indicated. To
handle larger requests, an application should read the HTTP request
directly using http::async_read
and then pass the request to the
appropriate overload of websocket::stream::accept
or
websocket::stream::async_accept
我通过 boost asio websocket 编写了一个 websocket 服务器。 当我尝试用 chrome 连接它时,它总是说连接失败。 日志显示缓冲区溢出。 尤其是在我打开了很多网站之后。
[2019-06-21 16:40:45.071345]-[0x00003130]-[error]:[NormalSession.cpp:75] acceptor 异步接受失败,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 endpoint{address, 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();
}));
}
这在文档中有解释:
If the request size exceeds the capacity of the stream's internal buffer, the error
websocket::buffer_overflow
will be indicated. To handle larger requests, an application should read the HTTP request directly usinghttp::async_read
and then pass the request to the appropriate overload ofwebsocket::stream::accept
orwebsocket::stream::async_accept