boost::asio::placeholders::error的正确使用

问题描述 投票:0回答:1

下面的代码片段可以在这个页面看到。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace boost::asio;
using ip::tcp;
using std::cout;
using std::endl;


class con_handler : public boost::enable_shared_from_this<con_handler>
{
private:
  tcp::socket sock;
  std::string message="Hello From Server!";
  enum { max_length = 1024 };
  char data[max_length];
    
public:
    
typedef boost::shared_ptr<con_handler> pointer;
 con_handler(boost::asio::io_service& io_service)
    : sock(io_service)
  {
  }

  static pointer create(boost::asio::io_service& io_service)
  {
    return pointer(new con_handler(io_service));
  }
  
  tcp::socket& socket()
  {
    return sock;
  }

  void start()
  {
    sock.async_read_some(
        boost::asio::buffer(data, max_length),
        boost::bind(&con_handler::handle_read,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));

    
    sock.async_write_some(
    boost::asio::buffer(message, max_length),
        boost::bind(&con_handler::handle_write, 
            shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
  }

  void handle_read(const boost::system::error_code& err,
                   size_t bytes_transferred)
  {
    if (!err) {
      cout << data << endl;

            

    } else {
std::cerr << "err (recv): " << err.message() << std::endl;
      sock.close();
    }
  }
  void handle_write(const boost::system::error_code& err,
               size_t bytes_transferred)
  {
    if (!err) {
 
    cout << "Server sent Hello message!"<< endl;
    
    } else {
      std::cerr << "err (recv): " << err.message() << std::endl;
      sock.close();
    }
  }

};

class Server {

private:
  tcp::acceptor acceptor_;

void start_accept()
  {
    // creates a socket
    con_handler::pointer connection =
      con_handler::create(acceptor_.get_io_service());

    // initiates an asynchronous accept operation 
    // to wait for a new connection. 
    acceptor_.async_accept(connection->socket(),
        boost::bind(&Server::handle_accept, this, connection,
          boost::asio::placeholders::error));
  }
public:
  Server(boost::asio::io_service& io_service): acceptor_(io_service, tcp::endpoint(tcp::v4(), 1234))
  { 
     start_accept();
}
    

  void handle_accept(con_handler::pointer connection,
                     const boost::system::error_code& err)
  {
    if (!err) {
      connection->start();
    }
    start_accept();
  }

};

int main(int argc, char *argv[])
{
  try 
{
    boost::asio::io_service io_service;   
    Server server(io_service);
    io_service.run();

} 
catch(std::exception& e) 
{
    std::cerr << e.what() << endl;
}
  return 0;
}

我认为代码片段应该改进。 由于

asio::placeholders::error
相当于
placehodlers::_1
并且
const boost::system::error_code& err
 void Server::handle_accept(con_handler::pointer connection, const boost::system::error_code& err)
的第二个参数,因此在下面的代码中
boost::asio::placeholders::error
应替换为
boost::placeholders::_2

    acceptor_.async_accept(connection->socket(),
        boost::bind(&Server::handle_accept, this, connection,
          boost::asio::placeholders::error));
c++ c++11 boost asio
1个回答
0
投票

如果您正在考虑参数 (_1) 的位置,那么它是正确的,因为处理程序签名是 (docs):

void handler(
    const boost::system::error_code& error // Result of operation.
);

请注意,bind 表达式 是您的处理程序,而不是

handle_accept
(它需要 3 个参数,包括 this 参数)。

如果您认为

_1
更具表现力,那就去吧。

同时,

  • 不要使用 Boost Bind 全局占位符(包括
    <boost/bind/bind.hpp>
    或配置编译器定义)
  • 更好的是用 std::bind 替换 boost::bind
  • 用 std::xxx 替换 boost::shared_ptr 和 boost::enable_shared_from_this
  • 使用类型别名而不是 typedef
  • 没有未使用的参数(如
    bytes_transferred
    );特别是不要依赖
    data
    的 NUL 终止!
  • 请勿乱用
    using namespace
  • 不要使用C风格的数组
  • 不要过度指定缓冲区大小(这是错误的来源)
  • 通过
    const&
  • 捕获异常
  • handle_XYZ
    设为私有
  • 出错时无需
    sock.close()
    ;您可以取消任何异步操作链并让
    con_handler
    的析构函数处理它。在您的情况下,即使
    cancel
    也是多余的,因为没有异步循环,并且单个读/写已经失败

简化到这一点:Live On Coliru

#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using namespace std::placeholders;
using asio::ip::tcp;

struct con_handler : std::enable_shared_from_this<con_handler> {
    using pointer = std::shared_ptr<con_handler>;
    con_handler(asio::any_io_executor ex) : sock(ex) {}

    tcp::socket& socket() { return sock; }

    void start() {
        auto self = shared_from_this();
        sock.async_read_some(asio::buffer(data), bind(&con_handler::handle_read, self, _1, _2));
        sock.async_write_some(asio::buffer(message), bind(&con_handler::handle_write, self, _1, _2));
    }

  private:
    void handle_read(boost::system::error_code const& err, size_t bytes_transferred) {
        std::cerr << "recv: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
        if (!err) {
            std::string_view msg(data.data(), bytes_transferred);
            std::cout << quoted(msg) << std::endl;
        }
        // else sock.cancel();
    }

    void handle_write(boost::system::error_code const& err, size_t bytes_transferred) {
        std::cerr << "sent: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
        if (!err)
            std::cout << "Server sent " << quoted(message) << std::endl;

        // else sock.cancel();
    }

    tcp::socket            sock;
    std::string            message = "Hello From Server!";
    std::array<char, 1024> data;
};

struct Server {
    Server(asio::any_io_executor ex) //
        : acceptor_(ex, tcp::endpoint(tcp::v4(), 1234)) {
        start_accept();
    }

    void handle_accept(con_handler::pointer connection, boost::system::error_code const& err) {
        if (!err)
            connection->start();

        start_accept();
    }

  private:
    tcp::acceptor acceptor_;

    void start_accept() {
        con_handler::pointer connection = std::make_shared<con_handler>(acceptor_.get_executor());

        acceptor_.async_accept(connection->socket(), bind(&Server::handle_accept, this, connection, _1));
    }
};

int main() try {
    asio::io_context ioc;
    Server           server(ioc.get_executor());
    ioc.run();
} catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
}

本地演示:

Asio版本:get_io_service()表示boost的古老版本

  • 而不是
    io_service
    引用,传递执行器,使代码耦合更少,更容易维护
  • 不要使用私有构造函数和
    new
    ,支持
    make_shared
  • 使用
    async_accept
    的移动接受重载,这样你就不必违反
    socket() { return sock; }
  • 的封装

文本协议:

  • 考虑进行逻辑阅读而不是
    read_some
    。例如。决定按行 IO,因此您可以读取直到第一个换行符(并且还可以使用换行符终止符写入消息)

v2 在 Coliru 上直播

#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using namespace std::placeholders;
using asio::ip::tcp;

struct con_handler : std::enable_shared_from_this<con_handler> {
    con_handler(tcp::socket s) : sock(std::move(s)) {}

    void start() {
        auto self = shared_from_this();
        do_read();
        async_write(sock, asio::buffer(message), //
                    bind(&con_handler::handle_write, self, _1, _2));
    }

  private:
    void do_read() {
        async_read_until(sock, asio::dynamic_buffer(response), "\n",
                         bind(&con_handler::handle_read, shared_from_this(), _1, _2));
    }

    void handle_read(boost::system::error_code const& err, size_t bytes_transferred) {
        std::cerr << "recv: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
        if (!err) {
            auto msg = response.substr(0, bytes_transferred - 1);
            response.erase(0, bytes_transferred);

            std::cout << quoted(msg) << std::endl;
            do_read();
        }

        // else sock.cancel();
    }

    void handle_write(boost::system::error_code const& err, size_t bytes_transferred) {
        std::cerr << "sent: " << bytes_transferred << "(" << err.message() << ")" << std::endl;
        if (!err)
            std::cout << "Server sent " << quoted(message) << std::endl;

        // else sock.cancel();
    }

    tcp::socket sock;
    std::string message = "Hello From Server!\n", response;
};

struct Server {
    Server(asio::any_io_executor ex) : acceptor_(ex, tcp::endpoint(tcp::v4(), 1234)) { accept_loop(); }

  private:
    tcp::acceptor acceptor_;

    void accept_loop() {
        acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket s) {
            if (!ec)
                std::make_shared<con_handler>(std::move(s))->start();

            accept_loop();
        });
    }
};

int main() try {
    asio::io_context ioc;
    Server           server(ioc.get_executor());
    ioc.run();
} catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
}

有更实用的本地演示:

© www.soinside.com 2019 - 2024. All rights reserved.