为什么在 asio 的示例中 tcp 接受器模式使用 shared_pointer 模型包装堆套接字,而 udp 使用堆栈套接字?

Why in asio's example the tcp acceptor pattern uses shared_pointer model wrapping heap socket, while udp use stack socket?

源代码: https://think-async.com/Asio/asio-1.18.0/doc/asio/tutorial/tutdaytime7/src.html

tcp_server 显示在堆上使用套接字的意图,由称为 tcp_connection.

的类型包装
class tcp_server
{
private:
  void start_accept()
  {
    tcp_connection::pointer new_connection =
      tcp_connection::create(io_context_);

    acceptor_.async_accept(new_connection->socket(),
        boost::bind(&tcp_server::handle_accept, this, new_connection,
          asio::placeholders::error));
  }

  void handle_accept(tcp_connection::pointer new_connection,
      const asio::error_code& error)
  {
    if (!error)
    {
      new_connection->start();
    }

    start_accept();
  }
  ...

套接字堆对象由 enable_shared_from_this aka shared_ptr

管理
class tcp_connection
  : public boost::enable_shared_from_this<tcp_connection>
{
public:
  typedef boost::shared_ptr<tcp_connection> pointer;

  static pointer create(asio::io_context& io_context)
  {
    return pointer(new tcp_connection(io_context));
  }

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

  void start()
  {
    message_ = make_daytime_string();

    asio::async_write(socket_, asio::buffer(message_),
        boost::bind(&tcp_connection::handle_write, shared_from_this()));
  }
  ...

而udp服务器只使用成员套接字。

class udp_server
{
public:
  udp_server(asio::io_context& io_context)
    : socket_(io_context, udp::endpoint(udp::v4(), 13))
  {
    start_receive();
  }

private:
  void start_receive()
  {
    socket_.async_receive_from(
        asio::buffer(recv_buffer_), remote_endpoint_,
        boost::bind(&udp_server::handle_receive, this,
          asio::placeholders::error));
  }

  void handle_receive(const asio::error_code& error)
  {
    if (!error)
    {
      boost::shared_ptr<std::string> message(
          new std::string(make_daytime_string()));

      socket_.async_send_to(asio::buffer(*message), remote_endpoint_,
          boost::bind(&udp_server::handle_send, this, message));

      start_receive();
    }
  }

  void handle_send(boost::shared_ptr<std::string> /*message*/)
  {
  }

  udp::socket socket_;
  udp::endpoint remote_endpoint_;
  boost::array<char, 1> recv_buffer_;
};

我的问题是为什么 tcp 接受器和 udp 套接字示例选择不同的方法?

只是为了展示不同的方法...
因此,考虑到上下文,您可以使用一种或另一种解决方案。

共享指针用于管理连接的生命周期。

在 TCP 的情况下,拥有多个连接更为常见,这会导致您可能拥有多个生命周期不相关的连接实例。

UDP 是无连接的,很多时候用于一次性消息。

事实上,您可以想出将共享指针与 UDP 一起使用的场景(例如,“逻辑连接”,例如通过 UDP 传输音频流)。

另外,反过来你可以用不同的方式解决生命难题(不管 TCP/UDP)。例如,我在这里使用了 std::list(为了参考稳定性)明智的单线程访问: ¹


¹ 我之前将其与此答案中的 shared_ptr 方法进行了比较:,您可能也会感兴趣