listener::on_accept 函数在 Boost 库中的 do_accept 函数结束时不被调用
listener::on_accept function is not called upon end of do_accept function in Boost library
我是使用 BOOST 库的新手。
我目前正在尝试使用 boost 库将数据包发送到 Web-socket 并苦苦挣扎。
我参考了这个 boost 网站 (https://www.boost.org/doc/libs/1_68_0/libs/beast/example/websocket/server/async/websocket_server_async.cpp) 中的模板。
首先,我通过运行在下面的线程函数中调用监听器构造函数。
DWORD WINAPI RunWebServerThread(LPVOID lpParameter)
{
int threads(1);
net::io_context ioc{ threads };
queue<PQN_DATA_PACKET *> *pconnectionQ = (queue<PQN_DATA_PACKET *> *)lpParameter;
auto const address = net::ip::make_address(LOCAL_IP);
// Create and launch a listening port
std::make_shared<listener>(ioc, tcp::endpoint{ address, SERVER_PORT_NUMBER }, pconnectionQ)->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v;
v.reserve(threads - 1);
for (auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ioc]
{
ioc.run();
});
ioc.run();
}
当make_shared函数为运行时,以下函数运行来自boost库。
// Start accepting incoming connections
void listener::run()
{
do_accept();
}
void listener::do_accept()
{
cout << "DO_ACCEPT LISTENER\n";
// The new connection gets its own strand
acceptor_.async_accept(
net::make_strand(ioc_),
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
cout << "DO_ACCEPT LISTENER END\n";
}
void listener::on_accept(beast::error_code ec, tcp::socket socket)
{
cout << "ON_ACCEPT LISTENER\n";
if (ec)
{
fail(ec, "accept");
}
else
{
// Create the session and run it
std::make_shared<session>(std::move(socket), pconnectionQ, ioc_)->run();
}
// Accept another connection
do_accept();
}
问题是 on_accept 函数似乎没有从 do_accept 函数调用 bind_front_handler 函数。
控制台应显示以下内容。
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
但是控制台只显示以下内容。
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
如您所见,on_accept() 函数从未被调用,我很难开始调试它,因为 boost 库太复杂了。
谁能建议我在这里做什么?
提前致谢!
您似乎有多个变量名称 ioc
。
具体来说,RunWebServerThread
中有一个是局部变量。然后是您在其他 listener
成员中使用的那个:ioc_
.
线程函数中的ioc
根据定义不能传到外面,所以我们知道它肯定是独立的实例。
还有很多遗留代码 smell/noise(例如 Win32 API 线程与 std::thread
混合在一起)。我会简化它。
另请注意,使用 std::cout << "\n"
并不能保证将消息刷新到标准输出。添加 std::flush
或使用 std::endl
(包括同花顺)。
假设您想与同一服务器的一个或多个侦听器共享 ioc/queues,这是对代码的重组:
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <memory>
#include <queue>
namespace net = boost::asio;
namespace beast = boost::beast;
using net::ip::tcp;
using beast::error_code;
static void fail(error_code ec, std::string_view msg) {
std::cerr << msg << ": " << ec.message() << std::endl;
throw std::runtime_error("fail");
}
struct PQN_DATA_PACKET {
};
struct session : std::enable_shared_from_this<session> {
session(tcp::socket&& socket) : _socket(std::move(socket)) {}
void run()
{
std::cout << "TODO session for " << _socket.remote_endpoint()
<< std::endl;
}
private:
tcp::socket _socket;
};
using Queue = std::queue<PQN_DATA_PACKET*>;
struct listener : std::enable_shared_from_this<listener> {
net::io_context& _ioc;
tcp::acceptor _acceptor{_ioc};
Queue& _connectionQ;
listener(net::io_context& ioc, tcp::endpoint ep, Queue& connectionQ)
: _ioc(ioc)
, _acceptor(ioc, ep)
, _connectionQ(connectionQ)
{
}
// Start accepting incoming connections
void run() { do_accept(); }
void do_accept()
{
std::cout << "DO_ACCEPT LISTENER" << std::endl;
// The new connection gets its own strand
_acceptor.async_accept( //
net::make_strand(_ioc),
beast::bind_front_handler(&listener::on_accept,
shared_from_this()));
std::cout << "DO_ACCEPT LISTENER END" << std::endl;
}
void on_accept(beast::error_code ec, tcp::socket socket)
{
std::cout << "ON_ACCEPT LISTENER" << std::endl;
if (ec) {
fail(ec, "accept");
} else {
// Create the session and run it
std::make_shared<session>(std::move(socket) /*, _connectionQ*/)
->run();
}
// Accept another connection
do_accept();
}
};
struct server {
net::io_context _ioc;
Queue _connectionQ;
void run(tcp::endpoint ep, unsigned nthreads = 1) {
std::make_shared<listener>(_ioc, ep, _connectionQ) //
->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v(nthreads);
for (auto& th : v)
th = std::thread([this] { _ioc.run(); });
for (auto& th : v)
if (th.joinable())
th.join();
}
};
int main() {
static uint16_t constexpr SERVER_PORT_NUMBER = 9797;
server srv;
srv.run({{}, SERVER_PORT_NUMBER}, 1);
}
打印
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45930
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45932
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45934
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45936
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45938
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45940
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45942
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45944
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45946
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45948
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
更多
我建议使用 boost::asio::thread_pool
而不是自己滚动(记住 Should the exception thrown by boost::asio::io_service::run() be caught? 例如)
请记住,在执行程序存在的情况下传递引用 ioc
是一种代码味道(您可能应该使用 _socket.get_executor()
或更本地地创建链?
我是使用 BOOST 库的新手。 我目前正在尝试使用 boost 库将数据包发送到 Web-socket 并苦苦挣扎。
我参考了这个 boost 网站 (https://www.boost.org/doc/libs/1_68_0/libs/beast/example/websocket/server/async/websocket_server_async.cpp) 中的模板。
首先,我通过运行在下面的线程函数中调用监听器构造函数。
DWORD WINAPI RunWebServerThread(LPVOID lpParameter)
{
int threads(1);
net::io_context ioc{ threads };
queue<PQN_DATA_PACKET *> *pconnectionQ = (queue<PQN_DATA_PACKET *> *)lpParameter;
auto const address = net::ip::make_address(LOCAL_IP);
// Create and launch a listening port
std::make_shared<listener>(ioc, tcp::endpoint{ address, SERVER_PORT_NUMBER }, pconnectionQ)->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v;
v.reserve(threads - 1);
for (auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ioc]
{
ioc.run();
});
ioc.run();
}
当make_shared函数为运行时,以下函数运行来自boost库。
// Start accepting incoming connections
void listener::run()
{
do_accept();
}
void listener::do_accept()
{
cout << "DO_ACCEPT LISTENER\n";
// The new connection gets its own strand
acceptor_.async_accept(
net::make_strand(ioc_),
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
cout << "DO_ACCEPT LISTENER END\n";
}
void listener::on_accept(beast::error_code ec, tcp::socket socket)
{
cout << "ON_ACCEPT LISTENER\n";
if (ec)
{
fail(ec, "accept");
}
else
{
// Create the session and run it
std::make_shared<session>(std::move(socket), pconnectionQ, ioc_)->run();
}
// Accept another connection
do_accept();
}
问题是 on_accept 函数似乎没有从 do_accept 函数调用 bind_front_handler 函数。
控制台应显示以下内容。
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
但是控制台只显示以下内容。
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
如您所见,on_accept() 函数从未被调用,我很难开始调试它,因为 boost 库太复杂了。
谁能建议我在这里做什么?
提前致谢!
您似乎有多个变量名称 ioc
。
具体来说,RunWebServerThread
中有一个是局部变量。然后是您在其他 listener
成员中使用的那个:ioc_
.
线程函数中的ioc
根据定义不能传到外面,所以我们知道它肯定是独立的实例。
还有很多遗留代码 smell/noise(例如 Win32 API 线程与 std::thread
混合在一起)。我会简化它。
另请注意,使用 std::cout << "\n"
并不能保证将消息刷新到标准输出。添加 std::flush
或使用 std::endl
(包括同花顺)。
假设您想与同一服务器的一个或多个侦听器共享 ioc/queues,这是对代码的重组:
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <memory>
#include <queue>
namespace net = boost::asio;
namespace beast = boost::beast;
using net::ip::tcp;
using beast::error_code;
static void fail(error_code ec, std::string_view msg) {
std::cerr << msg << ": " << ec.message() << std::endl;
throw std::runtime_error("fail");
}
struct PQN_DATA_PACKET {
};
struct session : std::enable_shared_from_this<session> {
session(tcp::socket&& socket) : _socket(std::move(socket)) {}
void run()
{
std::cout << "TODO session for " << _socket.remote_endpoint()
<< std::endl;
}
private:
tcp::socket _socket;
};
using Queue = std::queue<PQN_DATA_PACKET*>;
struct listener : std::enable_shared_from_this<listener> {
net::io_context& _ioc;
tcp::acceptor _acceptor{_ioc};
Queue& _connectionQ;
listener(net::io_context& ioc, tcp::endpoint ep, Queue& connectionQ)
: _ioc(ioc)
, _acceptor(ioc, ep)
, _connectionQ(connectionQ)
{
}
// Start accepting incoming connections
void run() { do_accept(); }
void do_accept()
{
std::cout << "DO_ACCEPT LISTENER" << std::endl;
// The new connection gets its own strand
_acceptor.async_accept( //
net::make_strand(_ioc),
beast::bind_front_handler(&listener::on_accept,
shared_from_this()));
std::cout << "DO_ACCEPT LISTENER END" << std::endl;
}
void on_accept(beast::error_code ec, tcp::socket socket)
{
std::cout << "ON_ACCEPT LISTENER" << std::endl;
if (ec) {
fail(ec, "accept");
} else {
// Create the session and run it
std::make_shared<session>(std::move(socket) /*, _connectionQ*/)
->run();
}
// Accept another connection
do_accept();
}
};
struct server {
net::io_context _ioc;
Queue _connectionQ;
void run(tcp::endpoint ep, unsigned nthreads = 1) {
std::make_shared<listener>(_ioc, ep, _connectionQ) //
->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v(nthreads);
for (auto& th : v)
th = std::thread([this] { _ioc.run(); });
for (auto& th : v)
if (th.joinable())
th.join();
}
};
int main() {
static uint16_t constexpr SERVER_PORT_NUMBER = 9797;
server srv;
srv.run({{}, SERVER_PORT_NUMBER}, 1);
}
打印
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45930
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45932
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45934
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45936
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45938
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45940
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45942
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45944
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45946
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
ON_ACCEPT LISTENER
TODO session for 127.0.0.1:45948
DO_ACCEPT LISTENER
DO_ACCEPT LISTENER END
更多
我建议使用 boost::asio::thread_pool
而不是自己滚动(记住 Should the exception thrown by boost::asio::io_service::run() be caught? 例如)
请记住,在执行程序存在的情况下传递引用 ioc
是一种代码味道(您可能应该使用 _socket.get_executor()
或更本地地创建链?