问题描述
我正在尝试通过连接握手传递套接字,并使用 std::bind
来执行此操作。我得到的编译问题(在一个连续块中,为了可读性我已经添加了空格)是:
'std::_Bind<_Functor(_Bound_args ...)>::_Bind(_Functor&&,_Args&& ...)
[with _Args = {socket_state**,std::function<void(socket_state*)>&,boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::executor>&,boost::asio::io_context&};
_Functor = void (*)(socket_state*,boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>&,boost::asio::io_context&);
_Bound_args = {socket_state**,std::function<void(socket_state*)>,boost::asio::executor>,boost::asio::io_context}]':
我的代码如下,错误出现在给 std::bind
的 boost::asio::acceptor.async_accept(socket,...)
参数和 accept_new_client
方法的参数
void start_server(std::function<void(socket_state*)>& func,tcp::acceptor& acceptor,boost::asio::io_context& context)
{
acceptor.listen();
// Start client connection loop
networking::wait_for_client(func,acceptor,context);
}
void wait_for_client(std::function<void(socket_state*)>& func,boost::asio::io_context& context)
{
boost::asio::ip::tcp::socket socket(context);
// socket_state is its own class which links a particular socket with an ID and buffer data
// it also holds a function to indicate which part of the connection handshake it needs to go to next
socket_state* state = new socket_state(func,&socket);
acceptor.async_accept(socket,std::bind(&networking::accept_new_client,state,func,context));
}
void accept_new_client(socket_state* state,std::function<void(socket_state*)>& func,boost::asio::io_context& context)
{
state->on_network_action(state);
wait_for_client(func,context);
}
看起来它们会匹配,但是您可以看到错误状态我的 std::bind
参数是 socket_state**
而不是 socket_state*
,而 boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::executor>&
而不是 {{1} }.
我也不知道“with _Args”与“_Bound_args”是什么。
解决方法
这段代码有很多问题。
共享指针似乎处于错误的抽象级别。您希望整个“连接”类型都具有共享生命周期,而不仅仅是套接字。就您而言,socket_state
是一个不错的选择。
无论如何,您的套接字是一个局部变量,您将一个陈旧的指针传递到 socket_state
内部。 Socket-state 看起来必然会泄露。
这样就永远行不通了。
接下来,绑定会急切地绑定所有参数,留下一个空签名。这不是 any overload 接受的 [没有双关语]。你需要匹配
让我们来看看 AcceptHandler。另外,我们不要绑定所有冗余参数(func
已经在 socket_stateremember,
io_context` 被过度共享等)。
总的来说,您似乎需要树立信心,了解您所在的州。例如。这条线是有症状的:
state->on_network_action(state);
由于 on_network_action
是 socket_state
的成员函数,因此永远不需要将 state
作为参数传递(它将是 this
隐式)。所有出现的 acceptor
和 contest
都是一样的。
演示
修复以上所有问题,使用 std::shared_ptr 和 bind(你已经这样做了),注意 placeholder::_1
接受 error_code 等)
#include <boost/asio.hpp>
#include <memory>
#include <iostream>
namespace ba = boost::asio;
using namespace std::chrono_literals;
using boost::system::error_code;
using ba::ip::tcp;
struct socket_state;
using Callback = std::function<void(socket_state&)>;
struct socket_state : std::enable_shared_from_this<socket_state> {
Callback _callback;
tcp::socket _socket;
template <typename Executor>
socket_state(Callback cb,Executor ex) : _callback(cb),_socket(ex)
{
}
void on_network_action() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct networking {
using StatePtr = std::shared_ptr<socket_state>;
explicit networking(ba::io_context& ctx,Callback callback)
: context(ctx),callback(callback)
{
}
ba::io_context& context;
tcp::acceptor acceptor {context,{{},8989}};
Callback callback;
void start_server()
{
std::cout << "start_server" << std::endl;
acceptor.listen();
wait_for_client(); // Start client connection loop
}
void stop_server() {
std::cout << "stop_server" << std::endl;
acceptor.cancel();
acceptor.close();
}
void wait_for_client()
{
std::cout << "wait_for_client" << std::endl;
// socket_state is its own class which links a particular socket with
// an ID and buffer data it also holds a function to indicate which
// part of the connection handshake it needs to go to next
auto state =
std::make_shared<socket_state>(callback,context.get_executor());
acceptor.async_accept(state->_socket,std::bind(&networking::accept_new_client,this,std::placeholders::_1,state));
}
void accept_new_client(error_code ec,StatePtr state)
{
if (ec) {
std::cout << "accept_new_client " << ec.message() << std::endl;
return;
}
std::cout << "accept_new_client " << state->_socket.remote_endpoint()
<< std::endl;
state->on_network_action();
wait_for_client();
}
};
int main() {
ba::io_context ctx;
networking server(ctx,[](socket_state&) {
std::cout << "This is our callback" << std::endl;
});
server.start_server();
ctx.run_for(5s);
server.stop_server();
ctx.run();
}
有一些随机连接:
start_server
wait_for_client
accept_new_client 127.0.0.1:54376
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54378
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54380
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54382
void socket_state::on_network_action()
wait_for_client
stop_server
accept_new_client Operation canceled
注意版本发表评论
// socket_state is its own class which links a particular socket with
// an ID and buffer data it also holds a function to indicate which
// part of the connection handshake it needs to go to next
不再是完整的谎言:)