我想在boost ASIO上为tcp客户端/服务器实现编写一个包装器。 boost ASIO的界面非常好,但必须包装的原因是能够用其他东西替换事件循环。在我们的用例中,我们需要为每个异步读取调用相同的处理函数,应用程序不需要为每个asyncRead调用传递处理程序。因此,一次注册处理程序会有所帮助。我试过的一种方法就是这样 -
template <class Connection>
struct TCPClient { // implements the interface with ASIO
Connection *_connection;
void setConnection (Connection *connection)
{
_connection = connection;
}
void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(),
[this] (ErrorType err, unsigned a) {
if (_connection) _connection->handleRead(err);
if (!err) asyncRead();
});
}
};
我可以用CRTP做类似的事情
class MyConnection : public TCPClient<MyConnection> {
void readHandler (TCPClient::ErrType err)
{
}
};
在TCPClient类中,asyncRead将是
void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(),
[this] (ErrorType err, unsigned a) {
((Connection *)this)->handleRead(err);
if (!err) asyncRead();
});
}
这种情况很有用,因为TCPClient和连接的生命周期是相同的。
或PBCP
template <typename Connection>
class TCPClient : public Connection {
void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(),
[this] (ErrorType err, unsigned a) {
Connection::handleRead(err);
if (!err) asyncRead();
});
}
};
我不认为实际上存在IS-A关系,而不是TCPCLient和Connection。如果这些方案中的任何一个都很好,我很困惑。 (我也想知道为什么ASIO没有一个方案来缓存处理程序一次并且每次调用它。在Async读取的情况下,通常没有返回上下文。在我们的例子中,读取消息的速度是最大的问题, Boost ASIO每次复制读取处理程序+内存分配到存储都非常糟糕。因此根据测试结果我们可能需要将事件循环更改为自定义的东西。
答案 0 :(得分:0)
我从这个意义上做了一些工作。 在您的CRTP基类中,您可以尝试创建一个模板参数化方法,该方法调用派生类并设置一个持有lamba的std::function,需要将其传递给async_read / write。
基类:
template <class Connection>
struct TCPClient { // implements the interface with ASIO
std::function<void(const boost::system::error&) handler{};
void registerConnectionHandler(std::function<void(const boost::system::error&)> &&impl)
{
static_cast<MyConnection*>(this)->registerConnectionHandler(std::forward<decltype(impl)>(impl));
}
void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(), handler);
}
};
在派生类中:
class MyConnection : public TCPClient<MyConnection> {
public:
void registerConnectionHandler(std::function<void(const boost::system::error&)> &&impl)
{
handler = std::move(impl);
}
};
另一种方法是在派生类中实现处理程序,而不使用带有std :: function的registerConnectionHandler,这可能是最好的方法:
class MyConnection : public TCPClient<MyConnection> {
public:
void registerConnectionHandler()
{
handler = [this](const boost::system::error &err)
{
// your stuff here
};
}
};