Boost::Beast:具有websocket管道的服务器 我正在编写一个带有Boost M兽1.70和MySQL 8 C连接器的C++ WebSoC服务器。服务器将同时连接多个客户端。其特殊性在于,每个客户机将向服务器执行一行100个websocket请求。对于我的服务器,每个请求都是“cpu轻”,但服务器对每个请求执行“时间重”的sql请求
我已经用websocket\u server\u coro.cpp示例启动了我的服务器。服务器步骤包括: 1) websocket阅读器 2) sql请求 3) 网匣 问题是,对于给定的用户,服务器在步骤2被“锁定”,并且在该步骤和步骤3完成之前无法读取。因此,100个请求被顺序地解决。这对于我的用例来说太慢了 我已经读到boost beast不可能实现非阻塞读/写。然而,我现在要做的是在一个协同程序中执行异步读取和异步写入Boost::Beast:具有websocket管道的服务器 我正在编写一个带有Boost M兽1.70和MySQL 8 C连接器的C++ WebSoC服务器。服务器将同时连接多个客户端。其特殊性在于,每个客户机将向服务器执行一行100个websocket请求。对于我的服务器,每个请求都是“cpu轻”,但服务器对每个请求执行“时间重”的sql请求,c++,boost-asio,boost-beast,C++,Boost Asio,Boost Beast,我已经用websocket\u server\u coro.cpp示例启动了我的服务器。服务器步骤包括: 1) websocket阅读器 2) sql请求 3) 网匣 问题是,对于给定的用户,服务器在步骤2被“锁定”,并且在该步骤和步骤3完成之前无法读取。因此,100个请求被顺序地解决。这对于我的用例来说太慢了 我已经读到boost beast不可能实现非阻塞读/写。然而,我现在要做的是在一个协同程序中执行异步读取和异步写入 void ServerCoro::accept(websocket::
void ServerCoro::accept(websocket::stream<beast::tcp_stream> &ws) {
beast::error_code ec;
ws.set_option(websocket::stream_base::timeout::suggested(beast::role_type::server));
ws.set_option(websocket::stream_base::decorator([](websocket::response_type &res) {
res.set(http::field::server, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-Server-coro");
}));
ws.async_accept(yield[ec]);
if (ec) return fail(ec, "accept");
while (!_bStop) {
beast::flat_buffer buffer;
ws.async_read(buffer, yield[ec]);
if (ec == websocket::error::closed) {
std::cout << "=> get closed" << std::endl;
return;
}
if (ec) return fail(ec, "read");
auto buffer_str = new std::string(boost::beast::buffers_to_string(buffer.cdata()));
net::post([&, buffer_str] {
// sql async request such as :
// while (status == (mysql_real_query_nonblocking(this->con, sqlRequest.c_str(), sqlRequest.size()))) {
// ioc.poll_one(ec);
// }
// more sql ...
ws.async_write(net::buffer(worker->getResponse()), yield[ec]); // this line is throwing void boost::coroutines::detail::pull_coroutine_impl<void>::pull(): Assertion `! is_running()' failed.
if (ec) return fail(ec, "write");
});
}
}
void服务器coro::accept(websocket::stream&ws){
beast::错误代码ec;
ws.set_选项(websocket::stream_base::timeout::suggered(beast::role_type::server));
ws.set_选项(websocket::stream_base::decorator([](websocket::response_type&res){
res.set(http::field::server,std::string(BOOST\u BEAST\u VERSION\u string)+“websocket服务器coro”);
}));
异步接受(收益率[ec]);
如果(ec)返回失败(ec,“接受”);
while(!\u bStop){
beast::flat_缓冲区;
异步读取(缓冲区,收益率[ec]);
如果(ec==websocket::error::closed){
std::cout getResponse()),yield[ec]);//此行正在抛出void boost::coroutines::detail::pull\u coroutine\u impl::pull():断言“!is\u running()”失败。
如果(ec)返回失败(ec,“写入”);
});
}
}
问题是具有async_write的行抛出错误:
void boost::coroutines::detail::pull\u coroutine\u impl::pull():断言`!正在运行()失败
如果将此行替换为sync_write,则它可以工作,但对于给定用户,服务器仍保持顺序。
我尝试在单线程服务器上执行此代码。我还尝试使用相同的串进行异步读取和异步写入。仍然存在断言错误
使用boost beast for websocket,这样的服务器不可能吗?
谢谢。根据Vinnie Falco的建议,我以“websocket聊天”和“异步服务器”为例重写了代码。以下是代码的最终工作结果:
void Session::on_read(beast::error_code ec,std::size_t bytes_transfer)
{
boost::忽略未使用的字节(传输的字节);
if(ec==websocket::error::closed)return;//这表示会话已关闭
如果(ec)返回失败(ec,“读取”);
net::post([&,that=shared\u from_this(),ss=std::make\u shared(std::move(boost::beast::buffers\u to_string(_buffer.cdata())))]{
/*在这里调用ioc.poll_one(ec)的Sql东西,对我来说,Sql响应进入下面使用的worker.getResponse()内部*/
net::dispatch(_wstrand,[&,that=shared_from_this(),sss=std::make_shared(worker.getResponse())]{
异步写入(sss);
});
});
_buffer.consume(_buffer.size());//我们从缓冲区中删除刚刚读取的内容
do_read();//进行另一次读取
}
无效会话::异步写入(const std::共享会话和消息){
_写消息。推回(消息);
如果(_writeMessages.size()>1){
BOOST_LOG_Trial(警告)您是否尝试将SQL工作分派到单独的线程池,然后将结果发布回web套接字连接的链?这应该允许您同时执行SQL操作。您需要实现传出消息队列,代码可以在“websocket chat”中找到Beast示例程序。它运行良好。我使用了“websocket聊天”和“async server”的示例。我将sql代码放在没有串的net::post中,websocket在串上写/读(带有异步写入的队列)。感谢Vinnie Falco的回复和您在boost beast上的工作。这看起来很棒,但仍然可以改进。由于您使用的是boost 1.70,您可以将链放在NextLayer对象上,并在构建websocket时对其进行初始化。然后,所有异步websocket操作都将自动使用该链不需要在呼叫站点使用bind_executor。文档中介绍了这一点。